diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/screens/Profile/Sections/Feed.tsx | 34 | ||||
-rw-r--r-- | src/screens/Profile/Sections/Labels.tsx | 13 | ||||
-rw-r--r-- | src/view/com/feeds/ProfileFeedgens.tsx | 43 | ||||
-rw-r--r-- | src/view/com/lists/ProfileLists.tsx | 43 | ||||
-rw-r--r-- | src/view/screens/Profile.tsx | 69 |
5 files changed, 144 insertions, 58 deletions
diff --git a/src/screens/Profile/Sections/Feed.tsx b/src/screens/Profile/Sections/Feed.tsx index 0a5e2208d..bc106fcfb 100644 --- a/src/screens/Profile/Sections/Feed.tsx +++ b/src/screens/Profile/Sections/Feed.tsx @@ -1,18 +1,19 @@ import React from 'react' -import {View} from 'react-native' +import {findNodeHandle, View} from 'react-native' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' -import {ListRef} from 'view/com/util/List' -import {Feed} from 'view/com/posts/Feed' -import {EmptyState} from 'view/com/util/EmptyState' +import {useQueryClient} from '@tanstack/react-query' + +import {isNative} from '#/platform/detection' import {FeedDescriptor} from '#/state/queries/post-feed' import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed' -import {LoadLatestBtn} from 'view/com/util/load-latest/LoadLatestBtn' -import {useQueryClient} from '@tanstack/react-query' import {truncateAndInvalidate} from '#/state/queries/util' -import {Text} from '#/view/com/util/text/Text' import {usePalette} from 'lib/hooks/usePalette' -import {isNative} from '#/platform/detection' +import {Text} from '#/view/com/util/text/Text' +import {Feed} from 'view/com/posts/Feed' +import {EmptyState} from 'view/com/util/EmptyState' +import {ListRef} from 'view/com/util/List' +import {LoadLatestBtn} from 'view/com/util/load-latest/LoadLatestBtn' import {SectionRef} from './types' interface FeedSectionProps { @@ -21,12 +22,20 @@ interface FeedSectionProps { isFocused: boolean scrollElRef: ListRef ignoreFilterFor?: string + setScrollViewTag: (tag: number | null) => void } export const ProfileFeedSection = React.forwardRef< SectionRef, FeedSectionProps >(function FeedSectionImpl( - {feed, headerHeight, isFocused, scrollElRef, ignoreFilterFor}, + { + feed, + headerHeight, + isFocused, + scrollElRef, + ignoreFilterFor, + setScrollViewTag, + }, ref, ) { const {_} = useLingui() @@ -50,6 +59,13 @@ export const ProfileFeedSection = React.forwardRef< return <EmptyState icon="feed" message={_(msg`This feed is empty!`)} /> }, [_]) + React.useEffect(() => { + if (isFocused && scrollElRef.current) { + const nativeTag = findNodeHandle(scrollElRef.current) + setScrollViewTag(nativeTag) + } + }, [isFocused, scrollElRef, setScrollViewTag]) + return ( <View> <Feed diff --git a/src/screens/Profile/Sections/Labels.tsx b/src/screens/Profile/Sections/Labels.tsx index 5ba8f00a5..f43e3633d 100644 --- a/src/screens/Profile/Sections/Labels.tsx +++ b/src/screens/Profile/Sections/Labels.tsx @@ -1,5 +1,5 @@ import React from 'react' -import {View} from 'react-native' +import {findNodeHandle, View} from 'react-native' import {useSafeAreaFrame} from 'react-native-safe-area-context' import { AppBskyLabelerDefs, @@ -32,6 +32,8 @@ interface LabelsSectionProps { moderationOpts: ModerationOpts scrollElRef: ListRef headerHeight: number + isFocused: boolean + setScrollViewTag: (tag: number | null) => void } export const ProfileLabelsSection = React.forwardRef< SectionRef, @@ -44,6 +46,8 @@ export const ProfileLabelsSection = React.forwardRef< moderationOpts, scrollElRef, headerHeight, + isFocused, + setScrollViewTag, }, ref, ) { @@ -63,6 +67,13 @@ export const ProfileLabelsSection = React.forwardRef< scrollToTop: onScrollToTop, })) + React.useEffect(() => { + if (isFocused && scrollElRef.current) { + const nativeTag = findNodeHandle(scrollElRef.current) + setScrollViewTag(nativeTag) + } + }, [isFocused, scrollElRef, setScrollViewTag]) + return ( <CenteredView style={{flex: 1, minHeight}} sideBorders> {isLabelerLoading ? ( diff --git a/src/view/com/feeds/ProfileFeedgens.tsx b/src/view/com/feeds/ProfileFeedgens.tsx index e9cf9e535..a006b11c0 100644 --- a/src/view/com/feeds/ProfileFeedgens.tsx +++ b/src/view/com/feeds/ProfileFeedgens.tsx @@ -1,22 +1,29 @@ import React from 'react' -import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native' +import { + findNodeHandle, + StyleProp, + StyleSheet, + View, + ViewStyle, +} from 'react-native' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' import {useQueryClient} from '@tanstack/react-query' -import {List, ListRef} from '../util/List' -import {FeedSourceCardLoaded} from './FeedSourceCard' -import {ErrorMessage} from '../util/error/ErrorMessage' -import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn' -import {Text} from '../util/text/Text' -import {usePalette} from 'lib/hooks/usePalette' -import {useProfileFeedgensQuery, RQKEY} from '#/state/queries/profile-feedgens' -import {logger} from '#/logger' -import {Trans, msg} from '@lingui/macro' + import {cleanError} from '#/lib/strings/errors' import {useTheme} from '#/lib/ThemeContext' -import {usePreferencesQuery} from '#/state/queries/preferences' +import {logger} from '#/logger' +import {isNative} from '#/platform/detection' import {hydrateFeedGenerator} from '#/state/queries/feed' +import {usePreferencesQuery} from '#/state/queries/preferences' +import {RQKEY, useProfileFeedgensQuery} from '#/state/queries/profile-feedgens' +import {usePalette} from 'lib/hooks/usePalette' import {FeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' -import {isNative} from '#/platform/detection' -import {useLingui} from '@lingui/react' +import {ErrorMessage} from '../util/error/ErrorMessage' +import {List, ListRef} from '../util/List' +import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn' +import {Text} from '../util/text/Text' +import {FeedSourceCardLoaded} from './FeedSourceCard' const LOADING = {_reactKey: '__loading__'} const EMPTY = {_reactKey: '__empty__'} @@ -34,13 +41,14 @@ interface ProfileFeedgensProps { enabled?: boolean style?: StyleProp<ViewStyle> testID?: string + setScrollViewTag: (tag: number | null) => void } export const ProfileFeedgens = React.forwardRef< SectionRef, ProfileFeedgensProps >(function ProfileFeedgensImpl( - {did, scrollElRef, headerOffset, enabled, style, testID}, + {did, scrollElRef, headerOffset, enabled, style, testID, setScrollViewTag}, ref, ) { const pal = usePalette('default') @@ -169,6 +177,13 @@ export const ProfileFeedgens = React.forwardRef< [error, refetch, onPressRetryLoadMore, pal, preferences, _], ) + React.useEffect(() => { + if (enabled && scrollElRef.current) { + const nativeTag = findNodeHandle(scrollElRef.current) + setScrollViewTag(nativeTag) + } + }, [enabled, scrollElRef, setScrollViewTag]) + return ( <View testID={testID} style={style}> <List diff --git a/src/view/com/lists/ProfileLists.tsx b/src/view/com/lists/ProfileLists.tsx index a47b25bed..003d1c60e 100644 --- a/src/view/com/lists/ProfileLists.tsx +++ b/src/view/com/lists/ProfileLists.tsx @@ -1,21 +1,28 @@ import React from 'react' -import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native' +import { + findNodeHandle, + StyleProp, + StyleSheet, + View, + ViewStyle, +} from 'react-native' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' import {useQueryClient} from '@tanstack/react-query' -import {List, ListRef} from '../util/List' -import {ListCard} from './ListCard' -import {ErrorMessage} from '../util/error/ErrorMessage' -import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn' -import {Text} from '../util/text/Text' -import {useAnalytics} from 'lib/analytics/analytics' -import {usePalette} from 'lib/hooks/usePalette' -import {useProfileListsQuery, RQKEY} from '#/state/queries/profile-lists' -import {logger} from '#/logger' -import {Trans, msg} from '@lingui/macro' + import {cleanError} from '#/lib/strings/errors' import {useTheme} from '#/lib/ThemeContext' -import {FeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' +import {logger} from '#/logger' import {isNative} from '#/platform/detection' -import {useLingui} from '@lingui/react' +import {RQKEY, useProfileListsQuery} from '#/state/queries/profile-lists' +import {useAnalytics} from 'lib/analytics/analytics' +import {usePalette} from 'lib/hooks/usePalette' +import {FeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' +import {ErrorMessage} from '../util/error/ErrorMessage' +import {List, ListRef} from '../util/List' +import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn' +import {Text} from '../util/text/Text' +import {ListCard} from './ListCard' const LOADING = {_reactKey: '__loading__'} const EMPTY = {_reactKey: '__empty__'} @@ -33,11 +40,12 @@ interface ProfileListsProps { enabled?: boolean style?: StyleProp<ViewStyle> testID?: string + setScrollViewTag: (tag: number | null) => void } export const ProfileLists = React.forwardRef<SectionRef, ProfileListsProps>( function ProfileListsImpl( - {did, scrollElRef, headerOffset, enabled, style, testID}, + {did, scrollElRef, headerOffset, enabled, style, testID, setScrollViewTag}, ref, ) { const pal = usePalette('default') @@ -171,6 +179,13 @@ export const ProfileLists = React.forwardRef<SectionRef, ProfileListsProps>( [error, refetch, onPressRetryLoadMore, pal, _], ) + React.useEffect(() => { + if (enabled && scrollElRef.current) { + const nativeTag = findNodeHandle(scrollElRef.current) + setScrollViewTag(nativeTag) + } + }, [enabled, scrollElRef, setScrollViewTag]) + return ( <View testID={testID} style={style}> <List diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx index 6073b9571..c391f8050 100644 --- a/src/view/screens/Profile.tsx +++ b/src/view/screens/Profile.tsx @@ -12,9 +12,7 @@ import {useFocusEffect} from '@react-navigation/native' import {useQueryClient} from '@tanstack/react-query' import {cleanError} from '#/lib/strings/errors' -import {isInvalidHandle} from '#/lib/strings/handles' import {useProfileShadow} from '#/state/cache/profile-shadow' -import {listenSoftReset} from '#/state/events' import {useLabelerInfoQuery} from '#/state/queries/labeler' import {resetProfilePostsQueries} from '#/state/queries/post-feed' import {useModerationOpts} from '#/state/queries/preferences' @@ -27,13 +25,17 @@ import {useAnalytics} from 'lib/analytics/analytics' import {useSetTitle} from 'lib/hooks/useSetTitle' import {ComposeIcon2} from 'lib/icons' import {CommonNavigatorParams, NativeStackScreenProps} from 'lib/routes/types' +import {useGate} from 'lib/statsig/statsig' import {combinedDisplayName} from 'lib/strings/display-names' +import {isInvalidHandle} from 'lib/strings/handles' import {colors, s} from 'lib/styles' +import {listenSoftReset} from 'state/events' import {PagerWithHeader} from 'view/com/pager/PagerWithHeader' import {ProfileHeader, ProfileHeaderLoading} from '#/screens/Profile/Header' import {ProfileFeedSection} from '#/screens/Profile/Sections/Feed' import {ProfileLabelsSection} from '#/screens/Profile/Sections/Labels' import {ScreenHider} from '#/components/moderation/ScreenHider' +import {ExpoScrollForwarderView} from '../../../modules/expo-scroll-forwarder' import {ProfileFeedgens} from '../com/feeds/ProfileFeedgens' import {ProfileLists} from '../com/lists/ProfileLists' import {ErrorScreen} from '../com/util/error/ErrorScreen' @@ -141,6 +143,7 @@ function ProfileScreenLoaded({ const setMinimalShellMode = useSetMinimalShellMode() const {openComposer} = useComposerControls() const {screen, track} = useAnalytics() + const shouldUseScrollableHeader = useGate('new_profile_scroll_component') const { data: labelerInfo, error: labelerError, @@ -152,6 +155,9 @@ function ProfileScreenLoaded({ const [currentPage, setCurrentPage] = React.useState(0) const {_} = useLingui() const setDrawerSwipeDisabled = useSetDrawerSwipeDisabled() + + const [scrollViewTag, setScrollViewTag] = React.useState<number | null>(null) + const postsSectionRef = React.useRef<SectionRef>(null) const repliesSectionRef = React.useRef<SectionRef>(null) const mediaSectionRef = React.useRef<SectionRef>(null) @@ -297,12 +303,9 @@ function ProfileScreenLoaded({ openComposer({mention}) }, [openComposer, currentAccount, track, profile]) - const onPageSelected = React.useCallback( - (i: number) => { - setCurrentPage(i) - }, - [setCurrentPage], - ) + const onPageSelected = React.useCallback((i: number) => { + setCurrentPage(i) + }, []) const onCurrentPageSelected = React.useCallback( (index: number) => { @@ -315,21 +318,38 @@ function ProfileScreenLoaded({ // = const renderHeader = React.useCallback(() => { - return ( - <ProfileHeader - profile={profile} - labeler={labelerInfo} - descriptionRT={hasDescription ? descriptionRT : null} - moderationOpts={moderationOpts} - hideBackButton={hideBackButton} - isPlaceholderProfile={showPlaceholder} - /> - ) + if (shouldUseScrollableHeader) { + return ( + <ExpoScrollForwarderView scrollViewTag={scrollViewTag}> + <ProfileHeader + profile={profile} + labeler={labelerInfo} + descriptionRT={hasDescription ? descriptionRT : null} + moderationOpts={moderationOpts} + hideBackButton={hideBackButton} + isPlaceholderProfile={showPlaceholder} + /> + </ExpoScrollForwarderView> + ) + } else { + return ( + <ProfileHeader + profile={profile} + labeler={labelerInfo} + descriptionRT={hasDescription ? descriptionRT : null} + moderationOpts={moderationOpts} + hideBackButton={hideBackButton} + isPlaceholderProfile={showPlaceholder} + /> + ) + } }, [ + shouldUseScrollableHeader, + scrollViewTag, profile, labelerInfo, - descriptionRT, hasDescription, + descriptionRT, moderationOpts, hideBackButton, showPlaceholder, @@ -349,7 +369,7 @@ function ProfileScreenLoaded({ onCurrentPageSelected={onCurrentPageSelected} renderHeader={renderHeader}> {showFiltersTab - ? ({headerHeight, scrollElRef}) => ( + ? ({headerHeight, isFocused, scrollElRef}) => ( <ProfileLabelsSection ref={labelsSectionRef} labelerInfo={labelerInfo} @@ -358,6 +378,8 @@ function ProfileScreenLoaded({ moderationOpts={moderationOpts} scrollElRef={scrollElRef as ListRef} headerHeight={headerHeight} + isFocused={isFocused} + setScrollViewTag={setScrollViewTag} /> ) : null} @@ -369,6 +391,7 @@ function ProfileScreenLoaded({ scrollElRef={scrollElRef as ListRef} headerOffset={headerHeight} enabled={isFocused} + setScrollViewTag={setScrollViewTag} /> ) : null} @@ -381,6 +404,7 @@ function ProfileScreenLoaded({ isFocused={isFocused} scrollElRef={scrollElRef as ListRef} ignoreFilterFor={profile.did} + setScrollViewTag={setScrollViewTag} /> ) : null} @@ -393,6 +417,7 @@ function ProfileScreenLoaded({ isFocused={isFocused} scrollElRef={scrollElRef as ListRef} ignoreFilterFor={profile.did} + setScrollViewTag={setScrollViewTag} /> ) : null} @@ -405,6 +430,7 @@ function ProfileScreenLoaded({ isFocused={isFocused} scrollElRef={scrollElRef as ListRef} ignoreFilterFor={profile.did} + setScrollViewTag={setScrollViewTag} /> ) : null} @@ -417,6 +443,7 @@ function ProfileScreenLoaded({ isFocused={isFocused} scrollElRef={scrollElRef as ListRef} ignoreFilterFor={profile.did} + setScrollViewTag={setScrollViewTag} /> ) : null} @@ -428,6 +455,7 @@ function ProfileScreenLoaded({ scrollElRef={scrollElRef as ListRef} headerOffset={headerHeight} enabled={isFocused} + setScrollViewTag={setScrollViewTag} /> ) : null} @@ -439,6 +467,7 @@ function ProfileScreenLoaded({ scrollElRef={scrollElRef as ListRef} headerOffset={headerHeight} enabled={isFocused} + setScrollViewTag={setScrollViewTag} /> ) : null} |