diff --git a/src/components/ClipClopTest/ClipClopList.tsx b/src/components/ClipClopTest/ClipClopList.tsx index 5cfab8f63e..7158135275 100644 --- a/src/components/ClipClopTest/ClipClopList.tsx +++ b/src/components/ClipClopTest/ClipClopList.tsx @@ -1,17 +1,15 @@ import React from 'react' -import { - FlatList, - LayoutChangeEvent, - ListRenderItemInfo, - View, - ViewToken, -} from 'react-native' +import {Button, FlatList, View, ViewToken} from 'react-native' -import {atoms as a, useTheme} from '#/alf' -import {ClipClop as ClipClopInterface} from '#/components/ClipClopTest/RandomClipClops' +import {useTheme} from '#/alf' +import {atoms as a} from '#/alf' +import { + ClipClop, + placeholderClops, +} from '#/components/ClipClopTest/RandomClipClops' import {Text} from '#/components/Typography' -function ClipClop({message}: {message: ClipClopInterface}) { +function ClipClopItem({item}: {item: ClipClop}) { const t = useTheme() return ( - {message.text} + {item.text} ) } -function renderItem({item}: ListRenderItemInfo) { - return +function renderItem({item}: {item: ClipClop}) { + return } -function keyExtractor(item: ClipClopInterface, index: number) { - return `${item.id}-${index}` -} +// Generate unique key list item. +export const generateUniqueKey = () => + `_${Math.random().toString(36).substr(2, 9)}` -function HeaderPlaceholder({height}: {height: number}) { - return -} +export const ClipClopList = () => { + const flatListRef = React.useRef(null) -export function ClipClopList({clipClops}: {clipClops: ClipClopInterface[]}) { - const flatlistRef = React.useRef(null) - const contentHeight = React.useRef(0) + // Whenever we reach the end (visually the top), we don't want to keep calling it. We will set `isFetching` to true + // once the request for new posts starts. Then, we will change it back to false after the content size changes. + const isFetching = React.useRef(false) - const totalClipClops = React.useRef(0) + // We use this to know if we should scroll after a new clop is added to the list + const isAtBottom = React.useRef(false) - const isAtBottom = React.useRef(true) - const [placeholderHeight, setPlaceholderHeight] = React.useState(0) + // Because the viewableItemsChanged callback won't have access to the updated state, we use a ref to store the + // total number of clops + const totalClops = React.useRef(10) - // This creates a placeholder that adjusts with the whitespace above the last chat item - const onScreenLayout = React.useCallback((e: LayoutChangeEvent) => { - setPlaceholderHeight(e.nativeEvent.layout.height) - }, []) - - const onContentSizeChange = React.useCallback( - (_: number, height: number) => { - if (isAtBottom.current) { - flatlistRef.current?.scrollToOffset({offset: height, animated: true}) - } - - contentHeight.current = height - totalClipClops.current = clipClops.length - }, - [clipClops], + const [clops, setClops] = React.useState( + Array.from(Array(10).keys()).map(n => ({ + id: generateUniqueKey(), + text: placeholderClops[n % placeholderClops.length], + })), ) + const addOldClops = () => { + setClops(prev => { + const oldClops: ClipClop[] = Array.from(Array(5).keys()).map(n => ({ + id: generateUniqueKey(), + text: + placeholderClops[n % placeholderClops.length] + generateUniqueKey(), + })) + + totalClops.current += oldClops.length + return prev.concat(oldClops) + }) + } + + const addNewClip = () => { + setClops(prev => { + const newClops = Array.from(Array(1).keys()) + .map(n => ({ + id: generateUniqueKey(), + text: + placeholderClops[n % placeholderClops.length] + generateUniqueKey(), + })) + .reverse() + + totalClops.current += newClops.length + return newClops.concat(prev) + }) + } + const [onViewableItemsChanged, viewabilityConfig] = React.useMemo(() => { return [ (info: {viewableItems: Array; changed: Array}) => { - const lastVisibleItem = - info.viewableItems[info.viewableItems.length - 1] - const lastViewableIndex = lastVisibleItem?.index ?? -1 + const firstVisibleIndex = info.viewableItems[0]?.index - isAtBottom.current = lastViewableIndex >= totalClipClops.current - 2 + isAtBottom.current = Number(firstVisibleIndex) < 2 + + console.log({ + firstVisibleIndex, + totalClops: totalClops.current, + isAtBottom: isAtBottom.current, + }) }, { itemVisiblePercentThreshold: 100, @@ -84,21 +105,50 @@ export function ClipClopList({clipClops}: {clipClops: ClipClopInterface[]}) { ] }, []) + const onContentSizeChange = React.useCallback( + (_: number, height: number) => { + if (isAtBottom.current) { + flatListRef.current?.scrollToOffset({offset: 0, animated: true}) + } + + isFetching.current = false + }, + [clops], + ) + + const onEndReached = () => { + if (isFetching.current) return + isFetching.current = true + + // We wouldn't actually use a timeout, but there would be a delay while loading + setTimeout(() => { + addOldClops() + }, 1000) + } + return ( - + +