add list footer to list list

This commit is contained in:
Samuel Newman
2025-07-01 12:24:01 +03:00
parent 4e8ef12881
commit a14228fd06
3 changed files with 36 additions and 65 deletions
+2 -2
View File
@@ -1,5 +1,5 @@
import React, {memo} from 'react' import {memo} from 'react'
import {StyleProp, View, ViewStyle} from 'react-native' import {type StyleProp, View, type ViewStyle} from 'react-native'
import {msg, Trans} from '@lingui/macro' import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
+2 -2
View File
@@ -1,4 +1,4 @@
import React, { import {
useCallback, useCallback,
useImperativeHandle, useImperativeHandle,
useMemo, useMemo,
@@ -119,7 +119,7 @@ function GifList({
[onSelectGif], [onSelectGif],
) )
const onEndReached = React.useCallback(() => { const onEndReached = useCallback(() => {
if (isFetchingNextPage || !hasNextPage || error) return if (isFetchingNextPage || !hasNextPage || error) return
fetchNextPage() fetchNextPage()
}, [isFetchingNextPage, hasNextPage, error, fetchNextPage]) }, [isFetchingNextPage, hasNextPage, error, fetchNextPage])
+15 -44
View File
@@ -1,28 +1,25 @@
import React from 'react' import {useCallback, useMemo, useState} from 'react'
import { import {
ActivityIndicator, ActivityIndicator,
FlatList as RNFlatList, type StyleProp,
RefreshControl,
StyleProp,
View, View,
ViewStyle, type ViewStyle,
} from 'react-native' } from 'react-native'
import {AppBskyGraphDefs as GraphDefs} from '@atproto/api' import {type AppBskyGraphDefs as GraphDefs} from '@atproto/api'
import {msg} from '@lingui/macro' import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {usePalette} from '#/lib/hooks/usePalette'
import {cleanError} from '#/lib/strings/errors' import {cleanError} from '#/lib/strings/errors'
import {s} from '#/lib/styles'
import {logger} from '#/logger' import {logger} from '#/logger'
import {useModerationOpts} from '#/state/preferences/moderation-opts' import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {MyListsFilter, useMyListsQuery} from '#/state/queries/my-lists' import {type MyListsFilter, useMyListsQuery} from '#/state/queries/my-lists'
import {ErrorMessage} from '#/view/com/util/error/ErrorMessage'
import {List} from '#/view/com/util/List'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
import {BulletList_Stroke2_Corner0_Rounded as ListIcon} from '#/components/icons/BulletList' import {BulletList_Stroke2_Corner0_Rounded as ListIcon} from '#/components/icons/BulletList'
import * as ListCard from '#/components/ListCard' import * as ListCard from '#/components/ListCard'
import {ListFooter} from '#/components/Lists'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
import {ErrorMessage} from '../util/error/ErrorMessage'
import {List} from '../util/List'
const LOADING = {_reactKey: '__loading__'} const LOADING = {_reactKey: '__loading__'}
const EMPTY = {_reactKey: '__empty__'} const EMPTY = {_reactKey: '__empty__'}
@@ -30,27 +27,24 @@ const ERROR_ITEM = {_reactKey: '__error__'}
export function MyLists({ export function MyLists({
filter, filter,
inline,
style, style,
renderItem, renderItem,
testID, testID,
}: { }: {
filter: MyListsFilter filter: MyListsFilter
inline?: boolean
style?: StyleProp<ViewStyle> style?: StyleProp<ViewStyle>
renderItem?: (list: GraphDefs.ListView, index: number) => JSX.Element renderItem?: (list: GraphDefs.ListView, index: number) => JSX.Element
testID?: string testID?: string
}) { }) {
const pal = usePalette('default')
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {_} = useLingui()
const moderationOpts = useModerationOpts() const moderationOpts = useModerationOpts()
const [isPTRing, setIsPTRing] = React.useState(false) const [isPTRing, setIsPTRing] = useState(false)
const {data, isFetching, isFetched, isError, error, refetch} = const {data, isFetching, isFetched, isError, error, refetch} =
useMyListsQuery(filter) useMyListsQuery(filter)
const isEmpty = !isFetching && !data?.length const isEmpty = !isFetching && !data?.length
const items = React.useMemo(() => { const items = useMemo(() => {
let items: any[] = [] let items: any[] = []
if (isError && isEmpty) { if (isError && isEmpty) {
items = items.concat([ERROR_ITEM]) items = items.concat([ERROR_ITEM])
@@ -85,7 +79,7 @@ export function MyLists({
// events // events
// = // =
const onRefresh = React.useCallback(async () => { const onRefresh = useCallback(async () => {
setIsPTRing(true) setIsPTRing(true)
try { try {
await refetch() await refetch()
@@ -98,7 +92,7 @@ export function MyLists({
// rendering // rendering
// = // =
const renderItemInner = React.useCallback( const renderItemInner = useCallback(
({item, index}: {item: any; index: number}) => { ({item, index}: {item: any; index: number}) => {
if (item === EMPTY) { if (item === EMPTY) {
return ( return (
@@ -162,30 +156,6 @@ export function MyLists({
[t, renderItem, error, onRefresh, emptyText], [t, renderItem, error, onRefresh, emptyText],
) )
if (inline) {
return (
<View testID={testID} style={style}>
{items.length > 0 && (
<RNFlatList
testID={testID ? `${testID}-flatlist` : undefined}
data={items}
keyExtractor={item => (item.uri ? item.uri : item._reactKey)}
renderItem={renderItemInner}
refreshControl={
<RefreshControl
refreshing={isPTRing}
onRefresh={onRefresh}
tintColor={pal.colors.text}
titleColor={pal.colors.text}
/>
}
contentContainerStyle={[s.contentContainer]}
removeClippedSubviews={true}
/>
)}
</View>
)
} else {
return ( return (
<View testID={testID} style={style}> <View testID={testID} style={style}>
{items.length > 0 && ( {items.length > 0 && (
@@ -196,13 +166,14 @@ export function MyLists({
renderItem={renderItemInner} renderItem={renderItemInner}
refreshing={isPTRing} refreshing={isPTRing}
onRefresh={onRefresh} onRefresh={onRefresh}
contentContainerStyle={[s.contentContainer]}
removeClippedSubviews={true} removeClippedSubviews={true}
desktopFixedHeight desktopFixedHeight
sideBorders={false} sideBorders={false}
ListFooterComponent={
<ListFooter error={cleanError(error)} onRetry={refetch} />
}
/> />
)} )}
</View> </View>
) )
} }
}