import React, {MutableRefObject} from 'react' import { ActivityIndicator, Dimensions, RefreshControl, StyleProp, View, ViewStyle, } from 'react-native' import {AppBskyActorDefs, AppBskyGraphDefs} from '@atproto/api' import {FlatList} from '../util/Views' import {observer} from 'mobx-react-lite' import {ProfileCardFeedLoadingPlaceholder} from '../util/LoadingPlaceholder' import {ErrorMessage} from '../util/error/ErrorMessage' import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn' import {ProfileCard} from '../profile/ProfileCard' import {Button} from '../util/forms/Button' import {ListModel} from 'state/models/content/list' import {useAnalytics} from 'lib/analytics/analytics' import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {OnScrollHandler} from 'lib/hooks/useOnMainScroll' import {logger} from '#/logger' import {useModalControls} from '#/state/modals' import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED' const LOADING_ITEM = {_reactKey: '__loading__'} const EMPTY_ITEM = {_reactKey: '__empty__'} const ERROR_ITEM = {_reactKey: '__error__'} const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'} export const ListItems = observer(function ListItemsImpl({ list, style, scrollElRef, onScroll, onPressTryAgain, renderHeader, renderEmptyState, testID, scrollEventThrottle, headerOffset = 0, desktopFixedHeightOffset, }: { list: ListModel style?: StyleProp scrollElRef?: MutableRefObject | null> onScroll: OnScrollHandler onPressTryAgain?: () => void renderHeader: () => JSX.Element renderEmptyState: () => JSX.Element testID?: string scrollEventThrottle?: number headerOffset?: number desktopFixedHeightOffset?: number }) { const pal = usePalette('default') const {track} = useAnalytics() const [isRefreshing, setIsRefreshing] = React.useState(false) const {isMobile} = useWebMediaQueries() const {openModal} = useModalControls() const data = React.useMemo(() => { let items: any[] = [] if (list.hasLoaded) { if (list.hasError) { items = items.concat([ERROR_ITEM]) } if (list.isEmpty) { items = items.concat([EMPTY_ITEM]) } else { items = items.concat(list.items) } if (list.loadMoreError) { items = items.concat([LOAD_MORE_ERROR_ITEM]) } } else if (list.isLoading) { items = items.concat([LOADING_ITEM]) } return items }, [ list.hasError, list.hasLoaded, list.isLoading, list.isEmpty, list.items, list.loadMoreError, ]) // events // = const onRefresh = React.useCallback(async () => { track('Lists:onRefresh') setIsRefreshing(true) try { await list.refresh() } catch (err) { logger.error('Failed to refresh lists', {error: err}) } setIsRefreshing(false) }, [list, track, setIsRefreshing]) const onEndReached = React.useCallback(async () => { track('Lists:onEndReached') try { await list.loadMore() } catch (err) { logger.error('Failed to load more lists', {error: err}) } }, [list, track]) const onPressRetryLoadMore = React.useCallback(() => { list.retryLoadMore() }, [list]) const onPressEditMembership = React.useCallback( (profile: AppBskyActorDefs.ProfileViewBasic) => { openModal({ name: 'user-add-remove-lists', subject: profile.did, displayName: profile.displayName || profile.handle, onAdd(listUri: string) { if (listUri === list.uri) { list.cacheAddMember(profile) } }, onRemove(listUri: string) { if (listUri === list.uri) { list.cacheRemoveMember(profile) } }, }) }, [openModal, list], ) // rendering // = const renderMemberButton = React.useCallback( (profile: AppBskyActorDefs.ProfileViewBasic) => { if (!list.isOwner) { return null } return (