import React, {memo} from 'react' import {FlatListProps, RefreshControl} from 'react-native' import {runOnJS, useSharedValue} from 'react-native-reanimated' import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED' import {usePalette} from '#/lib/hooks/usePalette' import {useScrollHandlers} from '#/lib/ScrollContext' import {addStyle} from 'lib/styles' import {FlatList_INTERNAL} from './Views' export type ListMethods = FlatList_INTERNAL export type ListProps = Omit< FlatListProps, | 'onMomentumScrollBegin' // Use ScrollContext instead. | 'onMomentumScrollEnd' // Use ScrollContext instead. | 'onScroll' // Use ScrollContext instead. | 'onScrollBeginDrag' // Use ScrollContext instead. | 'onScrollEndDrag' // Use ScrollContext instead. | 'refreshControl' // Pass refreshing and/or onRefresh instead. | 'contentOffset' // Pass headerOffset instead. > & { onScrolledDownChange?: (isScrolledDown: boolean) => void headerOffset?: number refreshing?: boolean onRefresh?: () => void containWeb?: boolean } export type ListRef = React.MutableRefObject const SCROLLED_DOWN_LIMIT = 200 function ListImpl( { 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) { onScrolledDownChange?.(didScrollDown) } const scrollHandler = useAnimatedScrollHandler({ onBeginDrag(e, ctx) { contextScrollHandlers.onBeginDrag?.(e, ctx) }, onEndDrag(e, ctx) { contextScrollHandlers.onEndDrag?.(e, ctx) }, onScroll(e, ctx) { contextScrollHandlers.onScroll?.(e, ctx) const didScrollDown = e.contentOffset.y > SCROLLED_DOWN_LIMIT if (isScrolledDown.value !== didScrollDown) { isScrolledDown.value = didScrollDown if (onScrolledDownChange != null) { runOnJS(handleScrolledDownChange)(didScrollDown) } } }, // Note: adding onMomentumBegin here makes simulator scroll // lag on Android. So either don't add it, or figure out why. onMomentumEnd(e, ctx) { contextScrollHandlers.onMomentumEnd?.(e, ctx) }, }) 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 ( ) } export const List = memo(React.forwardRef(ListImpl)) as ( props: ListProps & {ref?: React.Ref}, ) => React.ReactElement