about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/screens/Messages/Conversation/MessagesList.tsx81
-rw-r--r--src/view/com/util/List.web.tsx1
2 files changed, 47 insertions, 35 deletions
diff --git a/src/screens/Messages/Conversation/MessagesList.tsx b/src/screens/Messages/Conversation/MessagesList.tsx
index e00cf11cd..7068097fc 100644
--- a/src/screens/Messages/Conversation/MessagesList.tsx
+++ b/src/screens/Messages/Conversation/MessagesList.tsx
@@ -94,6 +94,9 @@ export function MessagesList() {
   // the bottom.
   const isAtBottom = useSharedValue(true)
 
+  // This will be used on web to assist in determing if we need to maintain the content offset
+  const isAtTop = useSharedValue(true)
+
   // Used to keep track of the current content height. We'll need this in `onScroll` so we know when to start allowing
   // onStartReached to fire.
   const contentHeight = useSharedValue(0)
@@ -116,6 +119,15 @@ export function MessagesList() {
   // we will not scroll whenever new items get prepended to the top.
   const onContentSizeChange = useCallback(
     (_: number, height: number) => {
+      // Because web does not have `maintainVisibleContentPosition` support, we will need to manually scroll to the
+      // previous offset whenever we add new content to the previous offset whenever we add new content to the list.
+      if (isWeb && isAtTop.value && hasInitiallyScrolled) {
+        flatListRef.current?.scrollToOffset({
+          animated: false,
+          offset: height - contentHeight.value,
+        })
+      }
+
       contentHeight.value = height
 
       // This number _must_ be the height of the MaybeLoader component
@@ -133,6 +145,7 @@ export function MessagesList() {
       contentHeight,
       hasInitiallyScrolled,
       isAtBottom.value,
+      isAtTop.value,
       isMomentumScrolling,
     ],
   )
@@ -164,6 +177,7 @@ export function MessagesList() {
       // Most apps have a little bit of space the user can scroll past while still automatically scrolling ot the bottom
       // when a new message is added, hence the 100 pixel offset
       isAtBottom.value = e.contentSize.height - 100 < bottomOffset
+      isAtTop.value = e.contentOffset.y <= 1
 
       // This number _must_ be the height of the MaybeLoader component.
       // We don't check for zero, because the `MaybeLoader` component is always present, even when not visible, which
@@ -172,7 +186,7 @@ export function MessagesList() {
         runOnJS(setHasInitiallyScrolled)(true)
       }
     },
-    [contentHeight.value, hasInitiallyScrolled, isAtBottom],
+    [contentHeight.value, hasInitiallyScrolled, isAtBottom, isAtTop],
   )
 
   const onMomentumEnd = React.useCallback(() => {
@@ -211,40 +225,37 @@ export function MessagesList() {
       keyboardVerticalOffset={isIOS ? topInset : 0}
       behavior="padding"
       contentContainerStyle={a.flex_1}>
-      {/* This view keeps the scroll bar and content within the CenterView on web, otherwise the entire window would scroll */}
-      {/* @ts-expect-error web only */}
-      <View style={[a.flex_1, isWeb && {'overflow-y': 'scroll'}]}>
-        {/* Custom scroll provider so that we can use the `onScroll` event in our custom List implementation */}
-        <ScrollProvider onScroll={onScroll} onMomentumEnd={onMomentumEnd}>
-          <List
-            ref={flatListRef}
-            data={chat.status === ConvoStatus.Ready ? chat.items : undefined}
-            renderItem={renderItem}
-            keyExtractor={keyExtractor}
-            disableVirtualization={true}
-            initialNumToRender={isWeb ? 50 : 25}
-            maxToRenderPerBatch={isWeb ? 50 : 25}
-            keyboardDismissMode="on-drag"
-            keyboardShouldPersistTaps="handled"
-            maintainVisibleContentPosition={{
-              minIndexForVisible: 1,
-            }}
-            contentContainerStyle={{paddingHorizontal: 10}}
-            removeClippedSubviews={false}
-            onContentSizeChange={onContentSizeChange}
-            onStartReached={onStartReached}
-            onScrollToIndexFailed={onScrollToIndexFailed}
-            scrollEventThrottle={100}
-            ListHeaderComponent={
-              <MaybeLoader
-                isLoading={
-                  chat.status === ConvoStatus.Ready && chat.isFetchingHistory
-                }
-              />
-            }
-          />
-        </ScrollProvider>
-      </View>
+      {/* Custom scroll provider so that we can use the `onScroll` event in our custom List implementation */}
+      <ScrollProvider onScroll={onScroll} onMomentumEnd={onMomentumEnd}>
+        <List
+          ref={flatListRef}
+          data={chat.status === ConvoStatus.Ready ? chat.items : undefined}
+          renderItem={renderItem}
+          keyExtractor={keyExtractor}
+          disableVirtualization={true}
+          initialNumToRender={isWeb ? 50 : 25}
+          maxToRenderPerBatch={isWeb ? 50 : 25}
+          keyboardDismissMode="on-drag"
+          keyboardShouldPersistTaps="handled"
+          maintainVisibleContentPosition={{
+            minIndexForVisible: 1,
+          }}
+          containWeb={true}
+          contentContainerStyle={{paddingHorizontal: 10}}
+          removeClippedSubviews={false}
+          onContentSizeChange={onContentSizeChange}
+          onStartReached={onStartReached}
+          onScrollToIndexFailed={onScrollToIndexFailed}
+          scrollEventThrottle={100}
+          ListHeaderComponent={
+            <MaybeLoader
+              isLoading={
+                chat.status === ConvoStatus.Ready && chat.isFetchingHistory
+              }
+            />
+          }
+        />
+      </ScrollProvider>
       <MessageInput onSendMessage={onSendMessage} scrollToEnd={scrollToEnd} />
     </KeyboardAvoidingView>
   )
diff --git a/src/view/com/util/List.web.tsx b/src/view/com/util/List.web.tsx
index e5c427f13..73000d95f 100644
--- a/src/view/com/util/List.web.tsx
+++ b/src/view/com/util/List.web.tsx
@@ -143,6 +143,7 @@ function ListImpl<ItemT>(
         scrollToTop() {
           getScrollableNode()?.scrollTo({top: 0})
         },
+
         scrollToOffset({
           animated,
           offset,