From 0090371011e2b5f2c93bf8196ec461c34bf1c999 Mon Sep 17 00:00:00 2001
From: Paul Frazee <pfrazee@gmail.com>
Date: Mon, 11 Sep 2023 17:41:00 -0700
Subject: Paginate the PostThread to avoid rendering too many posts and
 crashing the app on large threads (#1432)

---
 src/view/com/post-thread/PostThread.tsx | 39 ++++++++++++++++++++++++++++-----
 1 file changed, 33 insertions(+), 6 deletions(-)

(limited to 'src/view/com/post-thread/PostThread.tsx')

diff --git a/src/view/com/post-thread/PostThread.tsx b/src/view/com/post-thread/PostThread.tsx
index 59dfbe945..7a5a45771 100644
--- a/src/view/com/post-thread/PostThread.tsx
+++ b/src/view/com/post-thread/PostThread.tsx
@@ -3,6 +3,7 @@ import {runInAction} from 'mobx'
 import {observer} from 'mobx-react-lite'
 import {
   ActivityIndicator,
+  Pressable,
   RefreshControl,
   StyleSheet,
   TouchableOpacity,
@@ -47,6 +48,10 @@ const CHILD_SPINNER = {
   _reactKey: '__child_spinner__',
   _isHighlightedPost: false,
 }
+const LOAD_MORE = {
+  _reactKey: '__load_more__',
+  _isHighlightedPost: false,
+}
 const BOTTOM_COMPONENT = {
   _reactKey: '__bottom_component__',
   _isHighlightedPost: false,
@@ -74,10 +79,14 @@ export const PostThread = observer(function PostThread({
   const ref = useRef<FlatList>(null)
   const hasScrolledIntoView = useRef<boolean>(false)
   const [isRefreshing, setIsRefreshing] = React.useState(false)
+  const [maxVisible, setMaxVisible] = React.useState(100)
   const navigation = useNavigation<NavigationProp>()
   const posts = React.useMemo(() => {
     if (view.thread) {
-      const arr = [TOP_COMPONENT].concat(Array.from(flattenThread(view.thread)))
+      let arr = [TOP_COMPONENT].concat(Array.from(flattenThread(view.thread)))
+      if (arr.length > maxVisible) {
+        arr = arr.slice(0, maxVisible).concat([LOAD_MORE])
+      }
       if (view.isLoadingFromCache) {
         if (view.thread?.postRecord?.reply) {
           arr.unshift(PARENT_SPINNER)
@@ -89,7 +98,7 @@ export const PostThread = observer(function PostThread({
       return arr
     }
     return []
-  }, [view.isLoadingFromCache, view.thread])
+  }, [view.isLoadingFromCache, view.thread, maxVisible])
   useSetTitle(
     view.thread?.postRecord &&
       `${sanitizeDisplayName(
@@ -178,7 +187,7 @@ export const PostThread = observer(function PostThread({
         return <ComposePrompt onPressCompose={onPressReply} />
       } else if (item === DELETED) {
         return (
-          <View style={[pal.border, pal.viewLight, styles.missingItem]}>
+          <View style={[pal.border, pal.viewLight, styles.itemContainer]}>
             <Text type="lg-bold" style={pal.textLight}>
               Deleted post.
             </Text>
@@ -186,12 +195,30 @@ export const PostThread = observer(function PostThread({
         )
       } else if (item === BLOCKED) {
         return (
-          <View style={[pal.border, pal.viewLight, styles.missingItem]}>
+          <View style={[pal.border, pal.viewLight, styles.itemContainer]}>
             <Text type="lg-bold" style={pal.textLight}>
               Blocked post.
             </Text>
           </View>
         )
+      } else if (item === LOAD_MORE) {
+        return (
+          <Pressable
+            onPress={() => setMaxVisible(n => n + 50)}
+            style={[pal.border, pal.view, styles.itemContainer]}
+            accessibilityLabel="Load more posts"
+            accessibilityHint="">
+            <View
+              style={[
+                pal.viewLight,
+                {paddingHorizontal: 18, paddingVertical: 14, borderRadius: 6},
+              ]}>
+              <Text type="lg-medium" style={pal.text}>
+                Load more posts
+              </Text>
+            </View>
+          </Pressable>
+        )
       } else if (item === BOTTOM_COMPONENT) {
         // HACK
         // due to some complexities with how flatlist works, this is the easiest way
@@ -373,8 +400,8 @@ const styles = StyleSheet.create({
     paddingVertical: 14,
     borderRadius: 6,
   },
-  missingItem: {
-    borderTop: 1,
+  itemContainer: {
+    borderTopWidth: 1,
     paddingHorizontal: 18,
     paddingVertical: 18,
   },
-- 
cgit 1.4.1

