about summary refs log tree commit diff
path: root/src/view/com/post-thread/PostThread.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/com/post-thread/PostThread.tsx')
-rw-r--r--src/view/com/post-thread/PostThread.tsx63
1 files changed, 53 insertions, 10 deletions
diff --git a/src/view/com/post-thread/PostThread.tsx b/src/view/com/post-thread/PostThread.tsx
index 51f63dbb3..e7282cf83 100644
--- a/src/view/com/post-thread/PostThread.tsx
+++ b/src/view/com/post-thread/PostThread.tsx
@@ -20,25 +20,37 @@ import {ComposePrompt} from '../composer/Prompt'
 import {ErrorMessage} from '../util/error/ErrorMessage'
 import {Text} from '../util/text/Text'
 import {s} from 'lib/styles'
-import {isDesktopWeb, isMobileWeb} from 'platform/detection'
+import {isIOS, isDesktopWeb, isMobileWeb} from 'platform/detection'
 import {usePalette} from 'lib/hooks/usePalette'
 import {useSetTitle} from 'lib/hooks/useSetTitle'
 import {useNavigation} from '@react-navigation/native'
 import {NavigationProp} from 'lib/routes/types'
 import {sanitizeDisplayName} from 'lib/strings/display-names'
 
+const MAINTAIN_VISIBLE_CONTENT_POSITION = {minIndexForVisible: 0}
+
+const PARENT_SPINNER = {
+  _reactKey: '__parent_spinner__',
+  _isHighlightedPost: false,
+}
 const REPLY_PROMPT = {_reactKey: '__reply__', _isHighlightedPost: false}
 const DELETED = {_reactKey: '__deleted__', _isHighlightedPost: false}
 const BLOCKED = {_reactKey: '__blocked__', _isHighlightedPost: false}
+const CHILD_SPINNER = {
+  _reactKey: '__child_spinner__',
+  _isHighlightedPost: false,
+}
 const BOTTOM_COMPONENT = {
   _reactKey: '__bottom_component__',
   _isHighlightedPost: false,
 }
 type YieldedItem =
   | PostThreadItemModel
+  | typeof PARENT_SPINNER
   | typeof REPLY_PROMPT
   | typeof DELETED
   | typeof BLOCKED
+  | typeof PARENT_SPINNER
 
 export const PostThread = observer(function PostThread({
   uri,
@@ -55,10 +67,19 @@ export const PostThread = observer(function PostThread({
   const navigation = useNavigation<NavigationProp>()
   const posts = React.useMemo(() => {
     if (view.thread) {
-      return Array.from(flattenThread(view.thread)).concat([BOTTOM_COMPONENT])
+      const arr = Array.from(flattenThread(view.thread))
+      if (view.isLoadingFromCache) {
+        if (view.thread?.postRecord?.reply) {
+          arr.unshift(PARENT_SPINNER)
+        }
+        arr.push(CHILD_SPINNER)
+      } else {
+        arr.push(BOTTOM_COMPONENT)
+      }
+      return arr
     }
     return []
-  }, [view.thread])
+  }, [view.isLoadingFromCache, view.thread])
   useSetTitle(
     view.thread?.postRecord &&
       `${sanitizeDisplayName(
@@ -80,17 +101,15 @@ export const PostThread = observer(function PostThread({
     setIsRefreshing(false)
   }, [view, setIsRefreshing])
 
-  const onLayout = React.useCallback(() => {
+  const onContentSizeChange = React.useCallback(() => {
     const index = posts.findIndex(post => post._isHighlightedPost)
     if (index !== -1) {
       ref.current?.scrollToIndex({
         index,
         animated: false,
-        viewOffset: 40,
       })
     }
   }, [posts, ref])
-
   const onScrollToIndexFailed = React.useCallback(
     (info: {
       index: number
@@ -115,7 +134,13 @@ export const PostThread = observer(function PostThread({
 
   const renderItem = React.useCallback(
     ({item}: {item: YieldedItem}) => {
-      if (item === REPLY_PROMPT) {
+      if (item === PARENT_SPINNER) {
+        return (
+          <View style={styles.parentSpinner}>
+            <ActivityIndicator />
+          </View>
+        )
+      } else if (item === REPLY_PROMPT) {
         return <ComposePrompt onPressCompose={onPressReply} />
       } else if (item === DELETED) {
         return (
@@ -150,6 +175,12 @@ export const PostThread = observer(function PostThread({
             ]}
           />
         )
+      } else if (item === CHILD_SPINNER) {
+        return (
+          <View style={styles.childSpinner}>
+            <ActivityIndicator />
+          </View>
+        )
       } else if (item instanceof PostThreadItemModel) {
         return <PostThreadItem item={item} onPostReply={onRefresh} />
       }
@@ -247,6 +278,9 @@ export const PostThread = observer(function PostThread({
       ref={ref}
       data={posts}
       initialNumToRender={posts.length}
+      maintainVisibleContentPosition={
+        view.isFromCache ? MAINTAIN_VISIBLE_CONTENT_POSITION : undefined
+      }
       keyExtractor={item => item._reactKey}
       renderItem={renderItem}
       refreshControl={
@@ -257,10 +291,12 @@ export const PostThread = observer(function PostThread({
           titleColor={pal.colors.text}
         />
       }
-      onLayout={onLayout}
+      onContentSizeChange={
+        !isIOS || !view.isFromCache ? onContentSizeChange : undefined
+      }
       onScrollToIndexFailed={onScrollToIndexFailed}
       style={s.hContentRegion}
-      contentContainerStyle={s.contentContainerExtra}
+      contentContainerStyle={styles.contentContainerExtra}
     />
   )
 })
@@ -307,10 +343,17 @@ const styles = StyleSheet.create({
     paddingHorizontal: 18,
     paddingVertical: 18,
   },
+  parentSpinner: {
+    paddingVertical: 10,
+  },
+  childSpinner: {},
   bottomBorder: {
     borderBottomWidth: 1,
   },
   bottomSpacer: {
-    height: 200,
+    height: 400,
+  },
+  contentContainerExtra: {
+    paddingBottom: 500,
   },
 })