Add an intermediate List component

This commit is contained in:
Dan Abramov
2023-12-13 00:42:35 +00:00
parent 5fa43530f6
commit 7eb4ad6c29
24 changed files with 95 additions and 100 deletions
+3 -2
View File
@@ -13,7 +13,8 @@ import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {FeedDescriptor, FeedParams} from '#/state/queries/post-feed' import {FeedDescriptor, FeedParams} from '#/state/queries/post-feed'
import {ComposeIcon2} from 'lib/icons' import {ComposeIcon2} from 'lib/icons'
import {colors, s} from 'lib/styles' import {colors, s} from 'lib/styles'
import {FlatList, View, useWindowDimensions} from 'react-native' import {View, useWindowDimensions} from 'react-native'
import {ListMethods} from '../util/List'
import {Feed} from '../posts/Feed' import {Feed} from '../posts/Feed'
import {TextLink} from '../util/Link' import {TextLink} from '../util/Link'
import {FAB} from '../util/fab/FAB' import {FAB} from '../util/fab/FAB'
@@ -54,7 +55,7 @@ export function FeedPage({
const [onMainScroll, isScrolledDown, resetMainScroll] = useOnMainScroll() const [onMainScroll, isScrolledDown, resetMainScroll] = useOnMainScroll()
const {screen, track} = useAnalytics() const {screen, track} = useAnalytics()
const headerOffset = useHeaderOffset() const headerOffset = useHeaderOffset()
const scrollElRef = React.useRef<FlatList>(null) const scrollElRef = React.useRef<ListMethods>(null)
const [hasNew, setHasNew] = React.useState(false) const [hasNew, setHasNew] = React.useState(false)
const scrollToTop = React.useCallback(() => { const scrollToTop = React.useCallback(() => {
+4 -4
View File
@@ -1,4 +1,4 @@
import React, {MutableRefObject} from 'react' import React from 'react'
import { import {
Dimensions, Dimensions,
RefreshControl, RefreshControl,
@@ -8,7 +8,7 @@ import {
ViewStyle, ViewStyle,
} from 'react-native' } from 'react-native'
import {useQueryClient} from '@tanstack/react-query' import {useQueryClient} from '@tanstack/react-query'
import {FlatList} from '../util/Views' import {List, ListRef} from '../util/List'
import {FeedSourceCardLoaded} from './FeedSourceCard' import {FeedSourceCardLoaded} from './FeedSourceCard'
import {ErrorMessage} from '../util/error/ErrorMessage' import {ErrorMessage} from '../util/error/ErrorMessage'
import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn' import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
@@ -37,7 +37,7 @@ interface SectionRef {
interface ProfileFeedgensProps { interface ProfileFeedgensProps {
did: string did: string
scrollElRef: MutableRefObject<FlatList<any> | null> scrollElRef: ListRef
onScroll?: OnScrollHandler onScroll?: OnScrollHandler
scrollEventThrottle?: number scrollEventThrottle?: number
headerOffset: number headerOffset: number
@@ -188,7 +188,7 @@ export const ProfileFeedgens = React.forwardRef<
const scrollHandler = useAnimatedScrollHandler(onScroll || {}) const scrollHandler = useAnimatedScrollHandler(onScroll || {})
return ( return (
<View testID={testID} style={style}> <View testID={testID} style={style}>
<FlatList <List
testID={testID ? `${testID}-flatlist` : undefined} testID={testID ? `${testID}-flatlist` : undefined}
ref={scrollElRef} ref={scrollElRef}
data={items} data={items}
+4 -4
View File
@@ -1,4 +1,4 @@
import React, {MutableRefObject} from 'react' import React from 'react'
import { import {
ActivityIndicator, ActivityIndicator,
Dimensions, Dimensions,
@@ -8,7 +8,7 @@ import {
ViewStyle, ViewStyle,
} from 'react-native' } from 'react-native'
import {AppBskyActorDefs, AppBskyGraphDefs} from '@atproto/api' import {AppBskyActorDefs, AppBskyGraphDefs} from '@atproto/api'
import {FlatList} from '../util/Views' import {List, ListRef} from '../util/List'
import {ProfileCardFeedLoadingPlaceholder} from '../util/LoadingPlaceholder' import {ProfileCardFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
import {ErrorMessage} from '../util/error/ErrorMessage' import {ErrorMessage} from '../util/error/ErrorMessage'
import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn' import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
@@ -45,7 +45,7 @@ export function ListMembers({
}: { }: {
list: string list: string
style?: StyleProp<ViewStyle> style?: StyleProp<ViewStyle>
scrollElRef?: MutableRefObject<FlatList<any> | null> scrollElRef?: ListRef
onScroll: OnScrollHandler onScroll: OnScrollHandler
onPressTryAgain?: () => void onPressTryAgain?: () => void
renderHeader: () => JSX.Element renderHeader: () => JSX.Element
@@ -212,7 +212,7 @@ export function ListMembers({
const scrollHandler = useAnimatedScrollHandler(onScroll) const scrollHandler = useAnimatedScrollHandler(onScroll)
return ( return (
<View testID={testID} style={style}> <View testID={testID} style={style}>
<FlatList <List
testID={testID ? `${testID}-flatlist` : undefined} testID={testID ? `${testID}-flatlist` : undefined}
ref={scrollElRef} ref={scrollElRef}
data={items} data={items}
+2 -2
View File
@@ -15,7 +15,7 @@ import {ErrorMessage} from '../util/error/ErrorMessage'
import {Text} from '../util/text/Text' import {Text} from '../util/text/Text'
import {useAnalytics} from 'lib/analytics/analytics' import {useAnalytics} from 'lib/analytics/analytics'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {FlatList} from '../util/Views' import {List} from '../util/List'
import {s} from 'lib/styles' import {s} from 'lib/styles'
import {logger} from '#/logger' import {logger} from '#/logger'
import {Trans} from '@lingui/macro' import {Trans} from '@lingui/macro'
@@ -119,7 +119,7 @@ export function MyLists({
[error, onRefresh, renderItem, pal], [error, onRefresh, renderItem, pal],
) )
const FlatListCom = inline ? RNFlatList : FlatList const FlatListCom = inline ? RNFlatList : List
return ( return (
<View testID={testID} style={style}> <View testID={testID} style={style}>
{items.length > 0 && ( {items.length > 0 && (
+4 -4
View File
@@ -1,4 +1,4 @@
import React, {MutableRefObject} from 'react' import React from 'react'
import { import {
Dimensions, Dimensions,
RefreshControl, RefreshControl,
@@ -8,7 +8,7 @@ import {
ViewStyle, ViewStyle,
} from 'react-native' } from 'react-native'
import {useQueryClient} from '@tanstack/react-query' import {useQueryClient} from '@tanstack/react-query'
import {FlatList} from '../util/Views' import {List, ListRef} from '../util/List'
import {ListCard} from './ListCard' import {ListCard} from './ListCard'
import {ErrorMessage} from '../util/error/ErrorMessage' import {ErrorMessage} from '../util/error/ErrorMessage'
import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn' import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
@@ -36,7 +36,7 @@ interface SectionRef {
interface ProfileListsProps { interface ProfileListsProps {
did: string did: string
scrollElRef: MutableRefObject<FlatList<any> | null> scrollElRef: ListRef
onScroll?: OnScrollHandler onScroll?: OnScrollHandler
scrollEventThrottle?: number scrollEventThrottle?: number
headerOffset: number headerOffset: number
@@ -190,7 +190,7 @@ export const ProfileLists = React.forwardRef<SectionRef, ProfileListsProps>(
const scrollHandler = useAnimatedScrollHandler(onScroll || {}) const scrollHandler = useAnimatedScrollHandler(onScroll || {})
return ( return (
<View testID={testID} style={style}> <View testID={testID} style={style}>
<FlatList <List
testID={testID ? `${testID}-flatlist` : undefined} testID={testID ? `${testID}-flatlist` : undefined}
ref={scrollElRef} ref={scrollElRef}
data={items} data={items}
+5 -4
View File
@@ -1,5 +1,5 @@
import React, {MutableRefObject} from 'react' import React from 'react'
import {CenteredView, FlatList} from '../util/Views' import {CenteredView} from '../util/Views'
import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native' import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native'
import {FeedItem} from './FeedItem' import {FeedItem} from './FeedItem'
import {NotificationFeedLoadingPlaceholder} from '../util/LoadingPlaceholder' import {NotificationFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
@@ -15,6 +15,7 @@ import {useUnreadNotificationsApi} from '#/state/queries/notifications/unread'
import {logger} from '#/logger' import {logger} from '#/logger'
import {cleanError} from '#/lib/strings/errors' import {cleanError} from '#/lib/strings/errors'
import {useModerationOpts} from '#/state/queries/preferences' import {useModerationOpts} from '#/state/queries/preferences'
import {List, ListRef} from '../util/List'
const EMPTY_FEED_ITEM = {_reactKey: '__empty__'} const EMPTY_FEED_ITEM = {_reactKey: '__empty__'}
const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'} const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'}
@@ -26,7 +27,7 @@ export function Feed({
onScroll, onScroll,
ListHeaderComponent, ListHeaderComponent,
}: { }: {
scrollElRef?: MutableRefObject<FlatList<any> | null> scrollElRef?: ListRef
onPressTryAgain?: () => void onPressTryAgain?: () => void
onScroll?: OnScrollHandler onScroll?: OnScrollHandler
ListHeaderComponent?: () => JSX.Element ListHeaderComponent?: () => JSX.Element
@@ -146,7 +147,7 @@ export function Feed({
/> />
</CenteredView> </CenteredView>
)} )}
<FlatList <List
testID="notifsFeed" testID="notifsFeed"
ref={scrollElRef} ref={scrollElRef}
data={items} data={items}
+3 -3
View File
@@ -1,7 +1,6 @@
import * as React from 'react' import * as React from 'react'
import { import {
LayoutChangeEvent, LayoutChangeEvent,
FlatList,
ScrollView, ScrollView,
StyleSheet, StyleSheet,
View, View,
@@ -22,6 +21,7 @@ import {TabBar} from './TabBar'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {OnScrollHandler} from 'lib/hooks/useOnMainScroll' import {OnScrollHandler} from 'lib/hooks/useOnMainScroll'
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
import {ListMethods} from '../util/List'
const SCROLLED_DOWN_LIMIT = 200 const SCROLLED_DOWN_LIMIT = 200
@@ -30,7 +30,7 @@ export interface PagerWithHeaderChildParams {
isFocused: boolean isFocused: boolean
onScroll: OnScrollHandler onScroll: OnScrollHandler
isScrolledDown: boolean isScrolledDown: boolean
scrollElRef: React.MutableRefObject<FlatList<any> | ScrollView | null> scrollElRef: React.MutableRefObject<ListMethods | ScrollView | null>
} }
export interface PagerWithHeaderProps { export interface PagerWithHeaderProps {
@@ -331,7 +331,7 @@ function PagerItem({
isScrolledDown, isScrolledDown,
onScroll: scrollHandler, onScroll: scrollHandler,
scrollElRef: scrollElRef as React.MutableRefObject< scrollElRef: scrollElRef as React.MutableRefObject<
FlatList<any> | ScrollView | null ListMethods | ScrollView | null
>, >,
}) })
} }
+3 -2
View File
@@ -1,7 +1,8 @@
import React, {useCallback, useMemo, useState} from 'react' import React, {useCallback, useMemo, useState} from 'react'
import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native' import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native'
import {AppBskyFeedGetLikes as GetLikes} from '@atproto/api' import {AppBskyFeedGetLikes as GetLikes} from '@atproto/api'
import {CenteredView, FlatList} from '../util/Views' import {CenteredView} from '../util/Views'
import {List} from '../util/List'
import {ErrorMessage} from '../util/error/ErrorMessage' import {ErrorMessage} from '../util/error/ErrorMessage'
import {ProfileCardWithFollowBtn} from '../profile/ProfileCard' import {ProfileCardWithFollowBtn} from '../profile/ProfileCard'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
@@ -84,7 +85,7 @@ export function PostLikedBy({uri}: {uri: string}) {
// loaded // loaded
// = // =
return ( return (
<FlatList <List
data={likes} data={likes}
keyExtractor={item => item.actor.did} keyExtractor={item => item.actor.did}
refreshControl={ refreshControl={
+3 -2
View File
@@ -1,7 +1,8 @@
import React, {useMemo, useCallback, useState} from 'react' import React, {useMemo, useCallback, useState} from 'react'
import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native' import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native'
import {AppBskyActorDefs as ActorDefs} from '@atproto/api' import {AppBskyActorDefs as ActorDefs} from '@atproto/api'
import {CenteredView, FlatList} from '../util/Views' import {CenteredView} from '../util/Views'
import {List} from '../util/List'
import {ProfileCardWithFollowBtn} from '../profile/ProfileCard' import {ProfileCardWithFollowBtn} from '../profile/ProfileCard'
import {ErrorMessage} from '../util/error/ErrorMessage' import {ErrorMessage} from '../util/error/ErrorMessage'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
@@ -85,7 +86,7 @@ export function PostRepostedBy({uri}: {uri: string}) {
// loaded // loaded
// = // =
return ( return (
<FlatList <List
data={repostedBy} data={repostedBy}
keyExtractor={item => item.did} keyExtractor={item => item.did}
refreshControl={ refreshControl={
+4 -3
View File
@@ -8,7 +8,8 @@ import {
View, View,
} from 'react-native' } from 'react-native'
import {AppBskyFeedDefs} from '@atproto/api' import {AppBskyFeedDefs} from '@atproto/api'
import {CenteredView, FlatList} from '../util/Views' import {CenteredView} from '../util/Views'
import {List, ListMethods} from '../util/List'
import { import {
FontAwesomeIcon, FontAwesomeIcon,
FontAwesomeIconStyle, FontAwesomeIconStyle,
@@ -140,7 +141,7 @@ function PostThreadLoaded({
const {_} = useLingui() const {_} = useLingui()
const pal = usePalette('default') const pal = usePalette('default')
const {isTablet, isDesktop} = useWebMediaQueries() const {isTablet, isDesktop} = useWebMediaQueries()
const ref = useRef<FlatList>(null) const ref = useRef<ListMethods>(null)
const highlightedPostRef = useRef<View | null>(null) const highlightedPostRef = useRef<View | null>(null)
const needsScrollAdjustment = useRef<boolean>( const needsScrollAdjustment = useRef<boolean>(
!isNative || // web always uses scroll adjustment !isNative || // web always uses scroll adjustment
@@ -335,7 +336,7 @@ function PostThreadLoaded({
) )
return ( return (
<FlatList <List
ref={ref} ref={ref}
data={posts} data={posts}
initialNumToRender={!isNative ? posts.length : undefined} initialNumToRender={!isNative ? posts.length : undefined}
+4 -4
View File
@@ -1,4 +1,4 @@
import React, {memo, MutableRefObject} from 'react' import React, {memo} from 'react'
import { import {
ActivityIndicator, ActivityIndicator,
AppState, AppState,
@@ -10,7 +10,7 @@ import {
ViewStyle, ViewStyle,
} from 'react-native' } from 'react-native'
import {useQueryClient} from '@tanstack/react-query' import {useQueryClient} from '@tanstack/react-query'
import {FlatList} from '../util/Views' import {List, ListRef} from '../util/List'
import {PostFeedLoadingPlaceholder} from '../util/LoadingPlaceholder' import {PostFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
import {FeedErrorMessage} from './FeedErrorMessage' import {FeedErrorMessage} from './FeedErrorMessage'
import {FeedSlice} from './FeedSlice' import {FeedSlice} from './FeedSlice'
@@ -62,7 +62,7 @@ let Feed = ({
style?: StyleProp<ViewStyle> style?: StyleProp<ViewStyle>
enabled?: boolean enabled?: boolean
pollInterval?: number pollInterval?: number
scrollElRef?: MutableRefObject<FlatList<any> | null> scrollElRef?: ListRef
onHasNew?: (v: boolean) => void onHasNew?: (v: boolean) => void
onScroll?: OnScrollHandler onScroll?: OnScrollHandler
scrollEventThrottle?: number scrollEventThrottle?: number
@@ -273,7 +273,7 @@ let Feed = ({
const scrollHandler = useAnimatedScrollHandler(onScroll || {}) const scrollHandler = useAnimatedScrollHandler(onScroll || {})
return ( return (
<View testID={testID} style={style}> <View testID={testID} style={style}>
<FlatList <List
testID={testID ? `${testID}-flatlist` : undefined} testID={testID ? `${testID}-flatlist` : undefined}
ref={scrollElRef} ref={scrollElRef}
data={feedItems} data={feedItems}
+3 -2
View File
@@ -1,7 +1,8 @@
import React from 'react' import React from 'react'
import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native' import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native'
import {AppBskyActorDefs as ActorDefs} from '@atproto/api' import {AppBskyActorDefs as ActorDefs} from '@atproto/api'
import {CenteredView, FlatList} from '../util/Views' import {CenteredView} from '../util/Views'
import {List} from '../util/List'
import {ErrorMessage} from '../util/error/ErrorMessage' import {ErrorMessage} from '../util/error/ErrorMessage'
import {ProfileCardWithFollowBtn} from './ProfileCard' import {ProfileCardWithFollowBtn} from './ProfileCard'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
@@ -86,7 +87,7 @@ export function ProfileFollowers({name}: {name: string}) {
// loaded // loaded
// = // =
return ( return (
<FlatList <List
data={followers} data={followers}
keyExtractor={item => item.did} keyExtractor={item => item.did}
refreshControl={ refreshControl={
+3 -2
View File
@@ -1,7 +1,8 @@
import React from 'react' import React from 'react'
import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native' import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native'
import {AppBskyActorDefs as ActorDefs} from '@atproto/api' import {AppBskyActorDefs as ActorDefs} from '@atproto/api'
import {CenteredView, FlatList} from '../util/Views' import {CenteredView} from '../util/Views'
import {List} from '../util/List'
import {ErrorMessage} from '../util/error/ErrorMessage' import {ErrorMessage} from '../util/error/ErrorMessage'
import {ProfileCardWithFollowBtn} from './ProfileCard' import {ProfileCardWithFollowBtn} from './ProfileCard'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
@@ -86,7 +87,7 @@ export function ProfileFollows({name}: {name: string}) {
// loaded // loaded
// = // =
return ( return (
<FlatList <List
data={follows} data={follows}
keyExtractor={item => item.did} keyExtractor={item => item.did}
refreshControl={ refreshControl={
+15
View File
@@ -0,0 +1,15 @@
import React from 'react'
import {FlatListProps} from 'react-native'
import {FlatList_INTERNAL} from './Views'
export type ListMethods = FlatList_INTERNAL
export type ListProps<ItemT> = FlatListProps<ItemT>
export type ListRef = React.MutableRefObject<FlatList_INTERNAL | null>
function ListImpl<ItemT>(props: ListProps<ItemT>, ref: React.Ref<ListMethods>) {
return <FlatList_INTERNAL {...props} ref={ref} />
}
export const List = React.forwardRef(ListImpl) as <ItemT>(
props: ListProps<ItemT> & {ref?: React.Ref<ListMethods>},
) => React.ReactElement
+2 -2
View File
@@ -6,7 +6,7 @@ import {
View, View,
ScrollView, ScrollView,
} from 'react-native' } from 'react-native'
import {FlatList} from './Views' import {FlatList_INTERNAL} from './Views'
import {OnScrollCb} from 'lib/hooks/useOnMainScroll' import {OnScrollCb} from 'lib/hooks/useOnMainScroll'
import {useColorSchemeStyle} from 'lib/hooks/useColorSchemeStyle' import {useColorSchemeStyle} from 'lib/hooks/useColorSchemeStyle'
import {Text} from './text/Text' import {Text} from './text/Text'
@@ -110,7 +110,7 @@ export const ViewSelector = React.forwardRef<
[items], [items],
) )
return ( return (
<FlatList <FlatList_INTERNAL
ref={flatListRef} ref={flatListRef}
data={data} data={data}
keyExtractor={keyExtractor} keyExtractor={keyExtractor}
+1 -1
View File
@@ -1,6 +1,6 @@
import React from 'react' import React from 'react'
import {ViewProps} from 'react-native' import {ViewProps} from 'react-native'
export {FlatList, ScrollView} from 'react-native' export {FlatList as FlatList_INTERNAL, ScrollView} from 'react-native'
export function CenteredView({ export function CenteredView({
style, style,
sideBorders, sideBorders,
+1 -1
View File
@@ -2,7 +2,7 @@ import React from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import Animated from 'react-native-reanimated' import Animated from 'react-native-reanimated'
export const FlatList = Animated.FlatList export const FlatList_INTERNAL = Animated.FlatList
export const ScrollView = Animated.ScrollView export const ScrollView = Animated.ScrollView
export function CenteredView(props) { export function CenteredView(props) {
return <View {...props} /> return <View {...props} />
+1 -1
View File
@@ -49,7 +49,7 @@ export function CenteredView({
return <View style={style} {...props} /> return <View style={style} {...props} />
} }
export const FlatList = React.forwardRef(function FlatListImpl<ItemT>( export const FlatList_INTERNAL = React.forwardRef(function FlatListImpl<ItemT>(
{ {
contentContainerStyle, contentContainerStyle,
style, style,
+2 -2
View File
@@ -19,7 +19,7 @@ import {
import {ErrorMessage} from 'view/com/util/error/ErrorMessage' import {ErrorMessage} from 'view/com/util/error/ErrorMessage'
import debounce from 'lodash.debounce' import debounce from 'lodash.debounce'
import {Text} from 'view/com/util/text/Text' import {Text} from 'view/com/util/text/Text'
import {FlatList} from 'view/com/util/Views' import {List} from 'view/com/util/List'
import {useFocusEffect} from '@react-navigation/native' import {useFocusEffect} from '@react-navigation/native'
import {FeedSourceCard} from 'view/com/feeds/FeedSourceCard' import {FeedSourceCard} from 'view/com/feeds/FeedSourceCard'
import {Trans, msg} from '@lingui/macro' import {Trans, msg} from '@lingui/macro'
@@ -481,7 +481,7 @@ export function FeedsScreen(_props: Props) {
{preferences ? <View /> : <ActivityIndicator />} {preferences ? <View /> : <ActivityIndicator />}
<FlatList <List
style={[!isTabletOrDesktop && s.flex1, styles.list]} style={[!isTabletOrDesktop && s.flex1, styles.list]}
data={items} data={items}
keyExtractor={item => item.key} keyExtractor={item => item.key}
+3 -2
View File
@@ -1,5 +1,5 @@
import React from 'react' import React from 'react'
import {FlatList, View} from 'react-native' import {View} from 'react-native'
import {useFocusEffect} from '@react-navigation/native' import {useFocusEffect} from '@react-navigation/native'
import {useQueryClient} from '@tanstack/react-query' import {useQueryClient} from '@tanstack/react-query'
import { import {
@@ -9,6 +9,7 @@ import {
import {ViewHeader} from '../com/util/ViewHeader' import {ViewHeader} from '../com/util/ViewHeader'
import {Feed} from '../com/notifications/Feed' import {Feed} from '../com/notifications/Feed'
import {TextLink} from 'view/com/util/Link' import {TextLink} from 'view/com/util/Link'
import {ListMethods} from 'view/com/util/List'
import {LoadLatestBtn} from 'view/com/util/load-latest/LoadLatestBtn' import {LoadLatestBtn} from 'view/com/util/load-latest/LoadLatestBtn'
import {useOnMainScroll} from 'lib/hooks/useOnMainScroll' import {useOnMainScroll} from 'lib/hooks/useOnMainScroll'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
@@ -36,7 +37,7 @@ export function NotificationsScreen({}: Props) {
const {_} = useLingui() const {_} = useLingui()
const setMinimalShellMode = useSetMinimalShellMode() const setMinimalShellMode = useSetMinimalShellMode()
const [onMainScroll, isScrolledDown, resetMainScroll] = useOnMainScroll() const [onMainScroll, isScrolledDown, resetMainScroll] = useOnMainScroll()
const scrollElRef = React.useRef<FlatList>(null) const scrollElRef = React.useRef<ListMethods>(null)
const checkLatestRef = React.useRef<() => void | null>() const checkLatestRef = React.useRef<() => void | null>()
const {screen} = useAnalytics() const {screen} = useAnalytics()
const pal = usePalette('default') const pal = usePalette('default')
+9 -20
View File
@@ -5,7 +5,8 @@ import {AppBskyActorDefs, moderateProfile, ModerationOpts} from '@atproto/api'
import {msg, Trans} from '@lingui/macro' import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
import {CenteredView, FlatList} from '../com/util/Views' import {CenteredView} from '../com/util/Views'
import {ListRef} from '../com/util/List'
import {ScreenHider} from 'view/com/util/moderation/ScreenHider' import {ScreenHider} from 'view/com/util/moderation/ScreenHider'
import {Feed} from 'view/com/posts/Feed' import {Feed} from 'view/com/posts/Feed'
import {ProfileLists} from '../com/lists/ProfileLists' import {ProfileLists} from '../com/lists/ProfileLists'
@@ -285,9 +286,7 @@ function ProfileScreenLoaded({
headerHeight={headerHeight} headerHeight={headerHeight}
isFocused={isFocused} isFocused={isFocused}
isScrolledDown={isScrolledDown} isScrolledDown={isScrolledDown}
scrollElRef={ scrollElRef={scrollElRef as ListRef}
scrollElRef as React.MutableRefObject<FlatList<any> | null>
}
ignoreFilterFor={profile.did} ignoreFilterFor={profile.did}
/> />
)} )}
@@ -306,9 +305,7 @@ function ProfileScreenLoaded({
headerHeight={headerHeight} headerHeight={headerHeight}
isFocused={isFocused} isFocused={isFocused}
isScrolledDown={isScrolledDown} isScrolledDown={isScrolledDown}
scrollElRef={ scrollElRef={scrollElRef as ListRef}
scrollElRef as React.MutableRefObject<FlatList<any> | null>
}
ignoreFilterFor={profile.did} ignoreFilterFor={profile.did}
/> />
) )
@@ -321,9 +318,7 @@ function ProfileScreenLoaded({
headerHeight={headerHeight} headerHeight={headerHeight}
isFocused={isFocused} isFocused={isFocused}
isScrolledDown={isScrolledDown} isScrolledDown={isScrolledDown}
scrollElRef={ scrollElRef={scrollElRef as ListRef}
scrollElRef as React.MutableRefObject<FlatList<any> | null>
}
ignoreFilterFor={profile.did} ignoreFilterFor={profile.did}
/> />
)} )}
@@ -342,9 +337,7 @@ function ProfileScreenLoaded({
headerHeight={headerHeight} headerHeight={headerHeight}
isFocused={isFocused} isFocused={isFocused}
isScrolledDown={isScrolledDown} isScrolledDown={isScrolledDown}
scrollElRef={ scrollElRef={scrollElRef as ListRef}
scrollElRef as React.MutableRefObject<FlatList<any> | null>
}
ignoreFilterFor={profile.did} ignoreFilterFor={profile.did}
/> />
) )
@@ -354,9 +347,7 @@ function ProfileScreenLoaded({
<ProfileFeedgens <ProfileFeedgens
ref={feedsSectionRef} ref={feedsSectionRef}
did={profile.did} did={profile.did}
scrollElRef={ scrollElRef={scrollElRef as ListRef}
scrollElRef as React.MutableRefObject<FlatList<any> | null>
}
onScroll={onScroll} onScroll={onScroll}
scrollEventThrottle={1} scrollEventThrottle={1}
headerOffset={headerHeight} headerOffset={headerHeight}
@@ -369,9 +360,7 @@ function ProfileScreenLoaded({
<ProfileLists <ProfileLists
ref={listsSectionRef} ref={listsSectionRef}
did={profile.did} did={profile.did}
scrollElRef={ scrollElRef={scrollElRef as ListRef}
scrollElRef as React.MutableRefObject<FlatList<any> | null>
}
onScroll={onScroll} onScroll={onScroll}
scrollEventThrottle={1} scrollEventThrottle={1}
headerOffset={headerHeight} headerOffset={headerHeight}
@@ -400,7 +389,7 @@ interface FeedSectionProps {
headerHeight: number headerHeight: number
isFocused: boolean isFocused: boolean
isScrolledDown: boolean isScrolledDown: boolean
scrollElRef: React.MutableRefObject<FlatList<any> | null> scrollElRef: ListRef
ignoreFilterFor?: string ignoreFilterFor?: string
} }
const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>( const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
+4 -11
View File
@@ -1,11 +1,5 @@
import React, {useMemo, useCallback} from 'react' import React, {useMemo, useCallback} from 'react'
import { import {Dimensions, StyleSheet, View, ActivityIndicator} from 'react-native'
Dimensions,
StyleSheet,
View,
ActivityIndicator,
FlatList,
} from 'react-native'
import {NativeStackScreenProps} from '@react-navigation/native-stack' import {NativeStackScreenProps} from '@react-navigation/native-stack'
import {useNavigation} from '@react-navigation/native' import {useNavigation} from '@react-navigation/native'
import {useQueryClient} from '@tanstack/react-query' import {useQueryClient} from '@tanstack/react-query'
@@ -20,6 +14,7 @@ import {PagerWithHeader} from 'view/com/pager/PagerWithHeader'
import {ProfileSubpageHeader} from 'view/com/profile/ProfileSubpageHeader' import {ProfileSubpageHeader} from 'view/com/profile/ProfileSubpageHeader'
import {Feed} from 'view/com/posts/Feed' import {Feed} from 'view/com/posts/Feed'
import {TextLink} from 'view/com/util/Link' import {TextLink} from 'view/com/util/Link'
import {ListRef} from 'view/com/util/List'
import {Button} from 'view/com/util/forms/Button' import {Button} from 'view/com/util/forms/Button'
import {Text} from 'view/com/util/text/Text' import {Text} from 'view/com/util/text/Text'
import {RichText} from 'view/com/util/text/RichText' import {RichText} from 'view/com/util/text/RichText'
@@ -411,9 +406,7 @@ export function ProfileFeedScreenInner({
onScroll={onScroll} onScroll={onScroll}
headerHeight={headerHeight} headerHeight={headerHeight}
isScrolledDown={isScrolledDown} isScrolledDown={isScrolledDown}
scrollElRef={ scrollElRef={scrollElRef as ListRef}
scrollElRef as React.MutableRefObject<FlatList<any> | null>
}
isFocused={isFocused} isFocused={isFocused}
/> />
) : ( ) : (
@@ -500,7 +493,7 @@ interface FeedSectionProps {
onScroll: OnScrollHandler onScroll: OnScrollHandler
headerHeight: number headerHeight: number
isScrolledDown: boolean isScrolledDown: boolean
scrollElRef: React.MutableRefObject<FlatList<any> | null> scrollElRef: ListRef
isFocused: boolean isFocused: boolean
} }
const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>( const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
+7 -18
View File
@@ -1,11 +1,5 @@
import React, {useCallback, useMemo} from 'react' import React, {useCallback, useMemo} from 'react'
import { import {ActivityIndicator, Pressable, StyleSheet, View} from 'react-native'
ActivityIndicator,
FlatList,
Pressable,
StyleSheet,
View,
} from 'react-native'
import {useFocusEffect} from '@react-navigation/native' import {useFocusEffect} from '@react-navigation/native'
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
import {useNavigation} from '@react-navigation/native' import {useNavigation} from '@react-navigation/native'
@@ -22,6 +16,7 @@ import {EmptyState} from 'view/com/util/EmptyState'
import {RichText} from 'view/com/util/text/RichText' import {RichText} from 'view/com/util/text/RichText'
import {Button} from 'view/com/util/forms/Button' import {Button} from 'view/com/util/forms/Button'
import {TextLink} from 'view/com/util/Link' import {TextLink} from 'view/com/util/Link'
import {ListRef} from 'view/com/util/List'
import * as Toast from 'view/com/util/Toast' import * as Toast from 'view/com/util/Toast'
import {LoadLatestBtn} from 'view/com/util/load-latest/LoadLatestBtn' import {LoadLatestBtn} from 'view/com/util/load-latest/LoadLatestBtn'
import {FAB} from 'view/com/util/fab/FAB' import {FAB} from 'view/com/util/fab/FAB'
@@ -175,9 +170,7 @@ function ProfileListScreenLoaded({
<FeedSection <FeedSection
ref={feedSectionRef} ref={feedSectionRef}
feed={`list|${uri}`} feed={`list|${uri}`}
scrollElRef={ scrollElRef={scrollElRef as ListRef}
scrollElRef as React.MutableRefObject<FlatList<any> | null>
}
onScroll={onScroll} onScroll={onScroll}
headerHeight={headerHeight} headerHeight={headerHeight}
isScrolledDown={isScrolledDown} isScrolledDown={isScrolledDown}
@@ -187,9 +180,7 @@ function ProfileListScreenLoaded({
{({onScroll, headerHeight, isScrolledDown, scrollElRef}) => ( {({onScroll, headerHeight, isScrolledDown, scrollElRef}) => (
<AboutSection <AboutSection
ref={aboutSectionRef} ref={aboutSectionRef}
scrollElRef={ scrollElRef={scrollElRef as ListRef}
scrollElRef as React.MutableRefObject<FlatList<any> | null>
}
list={list} list={list}
onPressAddUser={onPressAddUser} onPressAddUser={onPressAddUser}
onScroll={onScroll} onScroll={onScroll}
@@ -224,9 +215,7 @@ function ProfileListScreenLoaded({
{({onScroll, headerHeight, isScrolledDown, scrollElRef}) => ( {({onScroll, headerHeight, isScrolledDown, scrollElRef}) => (
<AboutSection <AboutSection
list={list} list={list}
scrollElRef={ scrollElRef={scrollElRef as ListRef}
scrollElRef as React.MutableRefObject<FlatList<any> | null>
}
onPressAddUser={onPressAddUser} onPressAddUser={onPressAddUser}
onScroll={onScroll} onScroll={onScroll}
headerHeight={headerHeight} headerHeight={headerHeight}
@@ -618,7 +607,7 @@ interface FeedSectionProps {
onScroll: OnScrollHandler onScroll: OnScrollHandler
headerHeight: number headerHeight: number
isScrolledDown: boolean isScrolledDown: boolean
scrollElRef: React.MutableRefObject<FlatList<any> | null> scrollElRef: ListRef
isFocused: boolean isFocused: boolean
} }
const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>( const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
@@ -677,7 +666,7 @@ interface AboutSectionProps {
onScroll: OnScrollHandler onScroll: OnScrollHandler
headerHeight: number headerHeight: number
isScrolledDown: boolean isScrolledDown: boolean
scrollElRef: React.MutableRefObject<FlatList<any> | null> scrollElRef: ListRef
} }
const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>( const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>(
function AboutSectionImpl( function AboutSectionImpl(
+5 -4
View File
@@ -8,7 +8,8 @@ import {
Pressable, Pressable,
Platform, Platform,
} from 'react-native' } from 'react-native'
import {FlatList, ScrollView, CenteredView} from '#/view/com/util/Views' import {ScrollView, CenteredView} from '#/view/com/util/Views'
import {List} from '#/view/com/util/List'
import {AppBskyActorDefs, AppBskyFeedDefs, moderateProfile} from '@atproto/api' import {AppBskyActorDefs, AppBskyFeedDefs, moderateProfile} from '@atproto/api'
import {msg, Trans} from '@lingui/macro' import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
@@ -155,7 +156,7 @@ function SearchScreenSuggestedFollows() {
}, [currentAccount, setSuggestions, getSuggestedFollowsByActor]) }, [currentAccount, setSuggestions, getSuggestedFollowsByActor])
return suggestions.length ? ( return suggestions.length ? (
<FlatList <List
data={suggestions} data={suggestions}
renderItem={({item}) => <ProfileCardWithFollowBtn profile={item} noBg />} renderItem={({item}) => <ProfileCardWithFollowBtn profile={item} noBg />}
keyExtractor={item => item.did} keyExtractor={item => item.did}
@@ -243,7 +244,7 @@ function SearchScreenPostResults({query}: {query: string}) {
{isFetched ? ( {isFetched ? (
<> <>
{posts.length ? ( {posts.length ? (
<FlatList <List
data={items} data={items}
renderItem={({item}) => { renderItem={({item}) => {
if (item.type === 'post') { if (item.type === 'post') {
@@ -284,7 +285,7 @@ function SearchScreenUserResults({query}: {query: string}) {
return isFetched && results ? ( return isFetched && results ? (
<> <>
{results.length ? ( {results.length ? (
<FlatList <List
data={results} data={results}
renderItem={({item}) => ( renderItem={({item}) => (
<ProfileCardWithFollowBtn profile={item} noBg /> <ProfileCardWithFollowBtn profile={item} noBg />