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 (
-
+
+
item.id}
+ maintainVisibleContentPosition={{
+ minIndexForVisible: 1,
+ }}
renderItem={renderItem}
- keyExtractor={keyExtractor}
- // maintainVisibleContentPosition={{
- // minIndexForVisible: 0,
- // }}
- // ListHeaderComponent={}
+ onContentSizeChange={onContentSizeChange}
onViewableItemsChanged={onViewableItemsChanged}
viewabilityConfig={viewabilityConfig}
- ref={flatlistRef}
- onContentSizeChange={onContentSizeChange}
+ ref={flatListRef}
+ onScrollToIndexFailed={info => {
+ console.log('Failed to scroll to index', info)
+ }}
+ initialNumToRender={20}
+ maxToRenderPerBatch={20}
+ inverted
+ onEndReached={onEndReached}
/>
+
)
}
diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx
index 363cfc3b23..00bee8d7ef 100644
--- a/src/view/screens/Home.tsx
+++ b/src/view/screens/Home.tsx
@@ -51,52 +51,7 @@ type Props = NativeStackScreenProps
*/
export function HomeScreen(props: Props) {
- const lastMessageId = React.useRef(0)
- const [clipClops, setClipClops] = React.useState([])
-
- const addMessage = () => {
- lastMessageId.current += 1
-
- setClipClops(prev => {
- return [
- ...prev,
-
- {
- id: lastMessageId.current.toString(),
- text: `${
- placeholderClops[lastMessageId.current % placeholderClops.length]
- }`,
- },
- ]
- })
- }
-
- const addMessages = (count: number) => {
- for (let i = 0; i < count; i++) {
- addMessage()
- }
- }
-
- return (
-
-
-
-
-
- )
+ return
}
function HomeScreenReady({