diff --git a/src/lib/hooks/useOnMainScroll.ts b/src/lib/hooks/useOnMainScroll.ts index 41b35dd4..994a3571 100644 --- a/src/lib/hooks/useOnMainScroll.ts +++ b/src/lib/hooks/useOnMainScroll.ts @@ -2,6 +2,9 @@ import {useState} from 'react' import {NativeSyntheticEvent, NativeScrollEvent} from 'react-native' import {RootStoreModel} from 'state/index' +export type onMomentumScrollEndCb = ( + event: NativeSyntheticEvent, +) => void export type OnScrollCb = ( event: NativeSyntheticEvent, ) => void diff --git a/src/view/com/posts/Feed.tsx b/src/view/com/posts/Feed.tsx index 5b0110df..50398e70 100644 --- a/src/view/com/posts/Feed.tsx +++ b/src/view/com/posts/Feed.tsx @@ -14,7 +14,7 @@ import {ErrorMessage} from '../util/error/ErrorMessage' import {PostsFeedModel} from 'state/models/feeds/posts' import {FeedSlice} from './FeedSlice' import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn' -import {OnScrollCb} from 'lib/hooks/useOnMainScroll' +import {OnScrollCb, onMomentumScrollEndCb} from 'lib/hooks/useOnMainScroll' import {s} from 'lib/styles' import {useAnalytics} from 'lib/analytics' import {usePalette} from 'lib/hooks/usePalette' @@ -31,6 +31,8 @@ export const Feed = observer(function Feed({ scrollElRef, onPressTryAgain, onScroll, + scrollEventThrottle, + onMomentumScrollEnd, renderEmptyState, testID, headerOffset = 0, @@ -43,6 +45,8 @@ export const Feed = observer(function Feed({ scrollElRef?: MutableRefObject | null> onPressTryAgain?: () => void onScroll?: OnScrollCb + scrollEventThrottle?: number + onMomentumScrollEnd?: onMomentumScrollEndCb renderEmptyState?: () => JSX.Element testID?: string headerOffset?: number @@ -180,6 +184,8 @@ export const Feed = observer(function Feed({ contentContainerStyle={s.contentContainer} style={{paddingTop: headerOffset}} onScroll={onScroll} + scrollEventThrottle={scrollEventThrottle} + onMomentumScrollEnd={onMomentumScrollEnd} onEndReached={onEndReached} onEndReachedThreshold={0.6} removeClippedSubviews={true} diff --git a/src/view/screens/CustomFeed.tsx b/src/view/screens/CustomFeed.tsx index 952461c9..2316d7f0 100644 --- a/src/view/screens/CustomFeed.tsx +++ b/src/view/screens/CustomFeed.tsx @@ -1,4 +1,4 @@ -import React, {useMemo, useRef} from 'react' +import React, {useMemo, useRef, useState} from 'react' import {NativeStackScreenProps} from '@react-navigation/native-stack' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {usePalette} from 'lib/hooks/usePalette' @@ -25,6 +25,8 @@ import {useSetTitle} from 'lib/hooks/useSetTitle' import {shareUrl} from 'lib/sharing' import {toShareUrl} from 'lib/strings/url-helpers' import {Haptics} from 'lib/haptics' +import { LoadLatestBtn } from 'view/com/util/load-latest/LoadLatestBtn' +import { onMomentumScrollEndCb } from 'lib/hooks/useOnMainScroll' const HITSLOP = {top: 5, left: 5, bottom: 5, right: 5} @@ -48,7 +50,7 @@ export const CustomFeedScreen = withAuthRequired( return feed }, [store, uri]) const isPinned = store.me.savedFeeds.isPinned(uri) - + const [allowScrollToTop, setAllowScrollToTop] = useState(false) useSetTitle(currentFeed?.displayName) const onToggleSaved = React.useCallback(async () => { @@ -266,15 +268,29 @@ export const CustomFeedScreen = withAuthRequired( isPinned, ]) + const onMomentumScrollEnd: onMomentumScrollEndCb = React.useCallback((event) => { + if (event.nativeEvent.contentOffset.y > 200) { + setAllowScrollToTop(true) + } else { + setAllowScrollToTop(false) + } + }, []) + return ( + {allowScrollToTop ? { + scrollElRef.current?.scrollToOffset({offset: 0, animated: true}) + }} + label='Scroll to top' + /> : null} ) }),