diff --git a/src/lib/ScrollContext.tsx b/src/lib/ScrollContext.tsx new file mode 100644 index 0000000000..00b197bedc --- /dev/null +++ b/src/lib/ScrollContext.tsx @@ -0,0 +1,35 @@ +import React, {createContext, useContext, useMemo} from 'react' +import {ScrollHandlers} from 'react-native-reanimated' + +const ScrollContext = createContext>({ + onBeginDrag: undefined, + onEndDrag: undefined, + onScroll: undefined, +}) + +export function useScrollHandlers(): ScrollHandlers { + return useContext(ScrollContext) +} + +type ProviderProps = {children: React.ReactNode} & ScrollHandlers + +// Note: this completely *overrides* the parent handlers. +// It's up to you to compose them with the parent ones via useScrollHandlers() if needed. +export function ScrollProvider({ + children, + onBeginDrag, + onEndDrag, + onScroll, +}: ProviderProps) { + const handlers = useMemo( + () => ({ + onBeginDrag, + onEndDrag, + onScroll, + }), + [onBeginDrag, onEndDrag, onScroll], + ) + return ( + {children} + ) +} diff --git a/src/view/com/feeds/FeedPage.tsx b/src/view/com/feeds/FeedPage.tsx index f4327829b8..9c92a0dd5f 100644 --- a/src/view/com/feeds/FeedPage.tsx +++ b/src/view/com/feeds/FeedPage.tsx @@ -7,7 +7,7 @@ import {useNavigation} from '@react-navigation/native' import {useAnalytics} from 'lib/analytics/analytics' import {useQueryClient} from '@tanstack/react-query' import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed' -import {useOnMainScroll} from 'lib/hooks/useOnMainScroll' +import {MainScrollProvider} from '../util/MainScrollProvider' import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {useSetMinimalShellMode} from '#/state/shell' @@ -54,7 +54,6 @@ export function FeedPage({ const queryClient = useQueryClient() const {openComposer} = useComposerControls() const [isScrolledDown, setIsScrolledDown] = React.useState(false) - const onMainScroll = useOnMainScroll() const setMinimalShellMode = useSetMinimalShellMode() const {screen, track} = useAnalytics() const headerOffset = useHeaderOffset() @@ -168,20 +167,22 @@ export function FeedPage({ return ( - + + + {(isScrolledDown || hasNew) && ( ( ref: React.Ref, ) { const [isScrolledDown, setIsScrolledDown] = useState(false) + const scrollHandlers = useScrollHandlers() function handleScrolledDownChange(didScrollDown: boolean) { setIsScrolledDown(didScrollDown) onScrolledDownChange?.(didScrollDown) } - // TODO: This ignores the passed-in onScroll completely. const scrollHandler = useAnimatedScrollHandler({ - onScroll(e) { + onBeginDrag(e, ctx) { + scrollHandlers.onBeginDrag?.(e, ctx) + }, + onEndDrag(e, ctx) { + scrollHandlers.onEndDrag?.(e, ctx) + }, + onScroll(e, ctx) { const didScrollDown = e.contentOffset.y > SCROLLED_DOWN_LIMIT if (isScrolledDown !== didScrollDown) { runOnJS(handleScrolledDownChange)(didScrollDown) } + scrollHandlers.onScroll?.(e, ctx) }, }) diff --git a/src/lib/hooks/useOnMainScroll.ts b/src/view/com/util/MainScrollProvider.tsx similarity index 88% rename from src/lib/hooks/useOnMainScroll.ts rename to src/view/com/util/MainScrollProvider.tsx index 078e9d559b..31a4ef0c85 100644 --- a/src/lib/hooks/useOnMainScroll.ts +++ b/src/view/com/util/MainScrollProvider.tsx @@ -1,20 +1,17 @@ -import {useCallback, useMemo} from 'react' +import React, {useCallback} from 'react' +import {ScrollProvider} from '#/lib/ScrollContext' import {NativeScrollEvent} from 'react-native' import {useSetMinimalShellMode, useMinimalShellMode} from '#/state/shell' import {useShellLayout} from '#/state/shell/shell-layout' import {isWeb} from 'platform/detection' -import { - useSharedValue, - interpolate, - ScrollHandlers, -} from 'react-native-reanimated' +import {useSharedValue, interpolate} from 'react-native-reanimated' function clamp(num: number, min: number, max: number) { 'worklet' return Math.min(Math.max(num, min), max) } -export function useOnMainScroll(): ScrollHandlers { +export function MainScrollProvider({children}: {children: React.ReactNode}) { const {headerHeight} = useShellLayout() const mode = useMinimalShellMode() const setMode = useSetMinimalShellMode() @@ -89,14 +86,12 @@ export function useOnMainScroll(): ScrollHandlers { [headerHeight, mode, setMode, startDragOffset, startMode], ) - const scrollHandler: ScrollHandlers = useMemo( - () => ({ - onBeginDrag, - onEndDrag, - onScroll, - }), - [onBeginDrag, onEndDrag, onScroll], + return ( + + {children} + ) - - return scrollHandler } diff --git a/src/view/screens/Notifications.tsx b/src/view/screens/Notifications.tsx index 4b6838aea4..e28a67e370 100644 --- a/src/view/screens/Notifications.tsx +++ b/src/view/screens/Notifications.tsx @@ -11,7 +11,7 @@ import {Feed} from '../com/notifications/Feed' import {TextLink} from 'view/com/util/Link' import {ListMethods} from 'view/com/util/List' import {LoadLatestBtn} from 'view/com/util/load-latest/LoadLatestBtn' -import {useOnMainScroll} from 'lib/hooks/useOnMainScroll' +import {MainScrollProvider} from '../com/util/MainScrollProvider' import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {s, colors} from 'lib/styles' @@ -36,7 +36,6 @@ type Props = NativeStackScreenProps< export function NotificationsScreen({}: Props) { const {_} = useLingui() const setMinimalShellMode = useSetMinimalShellMode() - const onMainScroll = useOnMainScroll() const [isScrolledDown, setIsScrolledDown] = React.useState(false) const scrollElRef = React.useRef(null) const checkLatestRef = React.useRef<() => void | null>() @@ -132,11 +131,13 @@ export function NotificationsScreen({}: Props) { return ( - + + + {(isScrolledDown || hasNew) && (