Scroll feed search bar to top of screen on focus (#2602)

* Scroll feed search bar to top on focus

* update comment
zio/stable
Samuel Newman 2024-01-24 04:22:22 +00:00 committed by GitHub
parent 382383ca87
commit 94f39bb3eb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 36 additions and 1 deletions

View File

@ -1,5 +1,5 @@
import React from 'react' 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 {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {FontAwesomeIconStyle} from '@fortawesome/react-native-fontawesome' import {FontAwesomeIconStyle} from '@fortawesome/react-native-fontawesome'
import {ViewHeader} from 'view/com/util/ViewHeader' import {ViewHeader} from 'view/com/util/ViewHeader'
@ -34,6 +34,7 @@ import {
import {cleanError} from 'lib/strings/errors' import {cleanError} from 'lib/strings/errors'
import {useComposerControls} from '#/state/shell/composer' import {useComposerControls} from '#/state/shell/composer'
import {useSession} from '#/state/session' import {useSession} from '#/state/session'
import {isNative} from '#/platform/detection'
type Props = NativeStackScreenProps<FeedsTabNavigatorParams, 'Feeds'> type Props = NativeStackScreenProps<FeedsTabNavigatorParams, 'Feeds'>
@ -118,6 +119,7 @@ export function FeedsScreen(_props: Props) {
error: searchError, error: searchError,
} = useSearchPopularFeedsMutation() } = useSearchPopularFeedsMutation()
const {hasSession} = useSession() const {hasSession} = useSession()
const listRef = React.useRef<FlatList>(null)
/** /**
* A search query is present. We may not have search results yet. * A search query is present. We may not have search results yet.
@ -338,6 +340,35 @@ export function FeedsScreen(_props: Props) {
) )
}, [pal, _]) }, [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( const renderItem = React.useCallback(
({item}: {item: FlatlistSlice}) => { ({item}: {item: FlatlistSlice}) => {
if (item.type === 'error') { if (item.type === 'error') {
@ -415,6 +446,7 @@ export function FeedsScreen(_props: Props) {
onChangeQuery={onChangeQuery} onChangeQuery={onChangeQuery}
onPressCancelSearch={onPressCancelSearch} onPressCancelSearch={onPressCancelSearch}
onSubmitQuery={onSubmitQuery} onSubmitQuery={onSubmitQuery}
setIsInputFocused={onChangeSearchFocus}
style={{flex: 1, maxWidth: 250}} style={{flex: 1, maxWidth: 250}}
/> />
)} )}
@ -427,6 +459,7 @@ export function FeedsScreen(_props: Props) {
onChangeQuery={onChangeQuery} onChangeQuery={onChangeQuery}
onPressCancelSearch={onPressCancelSearch} onPressCancelSearch={onPressCancelSearch}
onSubmitQuery={onSubmitQuery} onSubmitQuery={onSubmitQuery}
setIsInputFocused={onChangeSearchFocus}
/> />
</View> </View>
)} )}
@ -469,6 +502,7 @@ export function FeedsScreen(_props: Props) {
onChangeQuery, onChangeQuery,
onPressCancelSearch, onPressCancelSearch,
onSubmitQuery, onSubmitQuery,
onChangeSearchFocus,
], ],
) )
@ -486,6 +520,7 @@ export function FeedsScreen(_props: Props) {
{preferences ? <View /> : <ActivityIndicator />} {preferences ? <View /> : <ActivityIndicator />}
<List <List
ref={listRef}
style={[!isTabletOrDesktop && s.flex1, styles.list]} style={[!isTabletOrDesktop && s.flex1, styles.list]}
data={items} data={items}
keyExtractor={item => item.key} keyExtractor={item => item.key}