From 4d380a0da1a3af938e1f101ac05f948d1f575343 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 10 Dec 2024 20:23:56 -0600 Subject: [PATCH] Lil baby button checkpoint --- src/components/Layout/index.tsx | 4 +- src/screens/Profile/ProfileFeed/index.tsx | 166 +++++++----------- .../components/ProfileSubpageHeader.tsx | 125 +++++++++++++ 3 files changed, 195 insertions(+), 100 deletions(-) create mode 100644 src/screens/Profile/components/ProfileSubpageHeader.tsx diff --git a/src/components/Layout/index.tsx b/src/components/Layout/index.tsx index d08505fbfd..8532cbbb49 100644 --- a/src/components/Layout/index.tsx +++ b/src/components/Layout/index.tsx @@ -21,6 +21,7 @@ export * as Header from '#/components/Layout/Header' export type ScreenProps = React.ComponentProps & { style?: StyleProp + noInsetTop?: boolean } /** @@ -28,6 +29,7 @@ export type ScreenProps = React.ComponentProps & { */ export const Screen = React.memo(function Screen({ style, + noInsetTop, ...props }: ScreenProps) { const {top} = useSafeAreaInsets() @@ -35,7 +37,7 @@ export const Screen = React.memo(function Screen({ <> {isWeb && } diff --git a/src/screens/Profile/ProfileFeed/index.tsx b/src/screens/Profile/ProfileFeed/index.tsx index dd2f8f12b5..84e31ed2fb 100644 --- a/src/screens/Profile/ProfileFeed/index.tsx +++ b/src/screens/Profile/ProfileFeed/index.tsx @@ -1,11 +1,12 @@ import React, {useCallback, useMemo} from 'react' -import {Pressable, StyleSheet, View} from 'react-native' +import {Pressable, StyleSheet, View, ScrollView} from 'react-native' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {msg, Plural, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useIsFocused, useNavigation} from '@react-navigation/native' import {NativeStackScreenProps} from '@react-navigation/native-stack' import {useQueryClient} from '@tanstack/react-query' +import {useAnimatedRef} from 'react-native-reanimated' import {HITSLOP_20} from '#/lib/constants' import {useHaptics} from '#/lib/haptics' @@ -38,7 +39,6 @@ import {useResolveUriQuery} from '#/state/queries/resolve-uri' import {truncateAndInvalidate} from '#/state/queries/util' import {useSession} from '#/state/session' import {useComposerControls} from '#/state/shell/composer' -import {PagerWithHeader} from '#/view/com/pager/PagerWithHeader' import {PostFeed} from '#/view/com/posts/PostFeed' import {ProfileSubpageHeader} from '#/view/com/profile/ProfileSubpageHeader' import {EmptyState} from '#/view/com/util/EmptyState' @@ -66,7 +66,7 @@ import * as Menu from '#/components/Menu' import {ReportDialog, useReportDialogControl} from '#/components/ReportDialog' import {RichText} from '#/components/RichText' -const SECTION_TITLES = ['Posts'] +import {ProfileSubpageHeader as NewHeader} from '#/screens/Profile/components/ProfileSubpageHeader' interface SectionRef { scrollToTop: () => void @@ -125,8 +125,10 @@ export function ProfileFeedScreen(props: Props) { } return resolvedUri ? ( - - + + + + ) : ( @@ -164,7 +166,6 @@ export function ProfileFeedScreenInner({ const reportDialogControl = useReportDialogControl() const {openComposer} = useComposerControls() const playHaptic = useHaptics() - const feedSectionRef = React.useRef(null) const isScreenFocused = useIsFocused() const {mutateAsync: addSavedFeeds, isPending: isAddSavedFeedPending} = @@ -257,18 +258,9 @@ export function ProfileFeedScreenInner({ reportDialogControl.open() }, [reportDialogControl]) - const onCurrentPageSelected = React.useCallback( - (index: number) => { - if (index === 0) { - feedSectionRef.current?.scrollToTop() - } - }, - [feedSectionRef], - ) - const renderHeader = useCallback(() => { return ( - <> + + - + ) }, [ _, @@ -392,6 +385,34 @@ export function ProfileFeedScreenInner({ isPending, ]) + const feed = `feedgen|${feedInfo.uri}` as FeedDescriptor + + const [hasNew, setHasNew] = React.useState(false) + const [isScrolledDown, setIsScrolledDown] = React.useState(false) + const queryClient = useQueryClient() + const feedFeedback = useFeedFeedback(feed, hasSession) + const scrollElRef = useAnimatedRef() as ListRef + + const onScrollToTop = useCallback(() => { + scrollElRef.current?.scrollToOffset({ + animated: isNative, + offset: 0, // -headerHeight, + }) + truncateAndInvalidate(queryClient, FEED_RQKEY(feed)) + setHasNew(false) + }, [scrollElRef, queryClient, feed, setHasNew]) + + React.useEffect(() => { + if (!isScreenFocused) { + return + } + return listenSoftReset(onScrollToTop) + }, [onScrollToTop, isScreenFocused]) + + const renderPostsEmpty = useCallback(() => { + return + }, [_]) + return ( <> - - {({headerHeight, scrollElRef, isFocused}) => ( - - )} - + + + + + + + + {(isScrolledDown || hasNew) && ( + + )} + {hasSession && ( ( - function FeedSectionImpl({feed, headerHeight, scrollElRef, isFocused}, ref) { - const {_} = useLingui() - const [hasNew, setHasNew] = React.useState(false) - const [isScrolledDown, setIsScrolledDown] = React.useState(false) - const queryClient = useQueryClient() - const isScreenFocused = useIsFocused() - const {hasSession} = useSession() - const feedFeedback = useFeedFeedback(feed, hasSession) - - const onScrollToTop = useCallback(() => { - scrollElRef.current?.scrollToOffset({ - animated: isNative, - offset: -headerHeight, - }) - truncateAndInvalidate(queryClient, FEED_RQKEY(feed)) - setHasNew(false) - }, [scrollElRef, headerHeight, queryClient, feed, setHasNew]) - - React.useImperativeHandle(ref, () => ({ - scrollToTop: onScrollToTop, - })) - - React.useEffect(() => { - if (!isScreenFocused) { - return - } - return listenSoftReset(onScrollToTop) - }, [onScrollToTop, isScreenFocused]) - - const renderPostsEmpty = useCallback(() => { - return - }, [_]) - - return ( - - - - - {(isScrolledDown || hasNew) && ( - - )} - - ) - }, -) - function AboutSection({ feedOwnerDid, feedRkey, diff --git a/src/screens/Profile/components/ProfileSubpageHeader.tsx b/src/screens/Profile/components/ProfileSubpageHeader.tsx new file mode 100644 index 0000000000..7b56405227 --- /dev/null +++ b/src/screens/Profile/components/ProfileSubpageHeader.tsx @@ -0,0 +1,125 @@ +import {View, Text as RNText} from 'react-native' +import {useLingui} from '@lingui/react' +import {msg, plural, Trans} from '@lingui/macro' +import {useSafeAreaInsets} from 'react-native-safe-area-context' + +import * as Layout from '#/components/Layout' +import {atoms as a, useTheme, useBreakpoints, web} from '#/alf' +import {UserAvatar} from '#/view/com/util/UserAvatar' +import {Text} from '#/components/Typography' +import {Pin_Stroke2_Corner0_Rounded as Pin} from '#/components/icons/Pin' +import {ChevronBottom_Stroke2_Corner0_Rounded as ChevronDown} from '#/components/icons/Chevron' +import {Button, ButtonIcon} from '#/components/Button' +import {sanitizeHandle} from '#/lib/strings/handles' + +export function ProfileSubpageHeader({ + title, + avatar, + creator, + likeCount, +}: { + title: string + avatar?: string + creator: {did: string; handle: string} + likeCount: number +}) { + const t = useTheme() + const {gtPhone, gtMobile} = useBreakpoints() + const {_} = useLingui() + const {top} = useSafeAreaInsets() + + return ( + + + + + + + + + + + + + ) +}