From 94f39bb3eb26a6ba2ae7f3eb72d78154006e2fca Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Wed, 24 Jan 2024 04:22:22 +0000 Subject: [PATCH] Scroll feed search bar to top of screen on focus (#2602) * Scroll feed search bar to top on focus * update comment --- src/view/screens/Feeds.tsx | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/view/screens/Feeds.tsx b/src/view/screens/Feeds.tsx index a913364d..9b3fd618 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 @@ -118,6 +119,7 @@ export function FeedsScreen(_props: Props) { error: searchError, } = useSearchPopularFeedsMutation() const {hasSession} = useSession() + const listRef = React.useRef(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} /> )} @@ -469,6 +502,7 @@ export function FeedsScreen(_props: Props) { onChangeQuery, onPressCancelSearch, onSubmitQuery, + onChangeSearchFocus, ], ) @@ -486,6 +520,7 @@ export function FeedsScreen(_props: Props) { {preferences ? : } item.key}