about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorPaul Frazee <pfrazee@gmail.com>2024-01-23 20:33:38 -0800
committerPaul Frazee <pfrazee@gmail.com>2024-01-23 20:33:38 -0800
commite628556d1f1f364bb6d5a1528a7a816ddd926a1d (patch)
tree2de08033b9dabda0f67379cf0dacb9cac27e0750 /src
parente273f4ed210b553b196e31b855637ad107eb4635 (diff)
parent94f39bb3eb26a6ba2ae7f3eb72d78154006e2fca (diff)
downloadvoidsky-e628556d1f1f364bb6d5a1528a7a816ddd926a1d.tar.zst
Merge branch 'main' of github.com:bluesky-social/social-app into main
Diffstat (limited to 'src')
-rw-r--r--src/view/screens/Feeds.tsx37
1 files changed, 36 insertions, 1 deletions
diff --git a/src/view/screens/Feeds.tsx b/src/view/screens/Feeds.tsx
index a913364d4..9b3fd6181 100644
--- a/src/view/screens/Feeds.tsx
+++ b/src/view/screens/Feeds.tsx
@@ -1,5 +1,5 @@
 import React from 'react'
-import {ActivityIndicator, StyleSheet, View} from 'react-native'
+import {ActivityIndicator, StyleSheet, View, type FlatList} from 'react-native'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import {FontAwesomeIconStyle} from '@fortawesome/react-native-fontawesome'
 import {ViewHeader} from 'view/com/util/ViewHeader'
@@ -34,6 +34,7 @@ import {
 import {cleanError} from 'lib/strings/errors'
 import {useComposerControls} from '#/state/shell/composer'
 import {useSession} from '#/state/session'
+import {isNative} from '#/platform/detection'
 
 type Props = NativeStackScreenProps<FeedsTabNavigatorParams, 'Feeds'>
 
@@ -118,6 +119,7 @@ export function FeedsScreen(_props: Props) {
     error: searchError,
   } = useSearchPopularFeedsMutation()
   const {hasSession} = useSession()
+  const listRef = React.useRef<FlatList>(null)
 
   /**
    * A search query is present. We may not have search results yet.
@@ -338,6 +340,35 @@ export function FeedsScreen(_props: Props) {
     )
   }, [pal, _])
 
+  const searchBarIndex = items.findIndex(
+    item => item.type === 'popularFeedsHeader',
+  )
+
+  const onChangeSearchFocus = React.useCallback(
+    (focus: boolean) => {
+      if (focus && searchBarIndex > -1) {
+        if (isNative) {
+          // scrollToIndex scrolls the exact right amount, so use if available
+          listRef.current?.scrollToIndex({
+            index: searchBarIndex,
+            animated: true,
+          })
+        } else {
+          // web implementation only supports scrollToOffset
+          // thus, we calculate the offset based on the index
+          // pixel values are estimates, I wasn't able to get it pixel perfect :(
+          const headerHeight = isMobile ? 43 : 53
+          const feedItemHeight = isMobile ? 49 : 58
+          listRef.current?.scrollToOffset({
+            offset: searchBarIndex * feedItemHeight - headerHeight,
+            animated: true,
+          })
+        }
+      }
+    },
+    [searchBarIndex, isMobile],
+  )
+
   const renderItem = React.useCallback(
     ({item}: {item: FlatlistSlice}) => {
       if (item.type === 'error') {
@@ -415,6 +446,7 @@ export function FeedsScreen(_props: Props) {
                   onChangeQuery={onChangeQuery}
                   onPressCancelSearch={onPressCancelSearch}
                   onSubmitQuery={onSubmitQuery}
+                  setIsInputFocused={onChangeSearchFocus}
                   style={{flex: 1, maxWidth: 250}}
                 />
               )}
@@ -427,6 +459,7 @@ export function FeedsScreen(_props: Props) {
                   onChangeQuery={onChangeQuery}
                   onPressCancelSearch={onPressCancelSearch}
                   onSubmitQuery={onSubmitQuery}
+                  setIsInputFocused={onChangeSearchFocus}
                 />
               </View>
             )}
@@ -469,6 +502,7 @@ export function FeedsScreen(_props: Props) {
       onChangeQuery,
       onPressCancelSearch,
       onSubmitQuery,
+      onChangeSearchFocus,
     ],
   )
 
@@ -486,6 +520,7 @@ export function FeedsScreen(_props: Props) {
       {preferences ? <View /> : <ActivityIndicator />}
 
       <List
+        ref={listRef}
         style={[!isTabletOrDesktop && s.flex1, styles.list]}
         data={items}
         keyExtractor={item => item.key}