From d36b91fe67225a9d3c79c8eeb3c80f6a72e9f73f Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 9 Feb 2024 05:00:50 +0000 Subject: Fix flashes and jumps when opening profile (#2815) * Don't reset the tree when profile loads fully * Give avatars a background color like placeholders * Prevent jumps due to rich text resolving * Rm log * Rm unused --- src/view/screens/Profile.tsx | 68 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 57 insertions(+), 11 deletions(-) (limited to 'src/view/screens/Profile.tsx') diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx index 9ca1b8c05..64e067593 100644 --- a/src/view/screens/Profile.tsx +++ b/src/view/screens/Profile.tsx @@ -1,7 +1,12 @@ import React, {useMemo} from 'react' import {StyleSheet, View} from 'react-native' import {useFocusEffect} from '@react-navigation/native' -import {AppBskyActorDefs, moderateProfile, ModerationOpts} from '@atproto/api' +import { + AppBskyActorDefs, + moderateProfile, + ModerationOpts, + RichText as RichTextAPI, +} from '@atproto/api' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' @@ -11,7 +16,7 @@ import {ScreenHider} from 'view/com/util/moderation/ScreenHider' import {Feed} from 'view/com/posts/Feed' import {ProfileLists} from '../com/lists/ProfileLists' import {ProfileFeedgens} from '../com/feeds/ProfileFeedgens' -import {ProfileHeader} from '../com/profile/ProfileHeader' +import {ProfileHeader, ProfileHeaderLoading} from '../com/profile/ProfileHeader' import {PagerWithHeader} from 'view/com/pager/PagerWithHeader' import {ErrorScreen} from '../com/util/error/ErrorScreen' import {EmptyState} from '../com/util/EmptyState' @@ -28,7 +33,7 @@ import { import {useResolveDidQuery} from '#/state/queries/resolve-uri' import {useProfileQuery} from '#/state/queries/profile' import {useProfileShadow} from '#/state/cache/profile-shadow' -import {useSession} from '#/state/session' +import {useSession, getAgent} from '#/state/session' import {useModerationOpts} from '#/state/queries/preferences' import {useProfileExtraInfoQuery} from '#/state/queries/profile-extra-info' import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed' @@ -87,14 +92,10 @@ export function ProfileScreen({route}: Props) { }, [profile?.viewer?.blockedBy, resolvedDid]) // Most pushes will happen here, since we will have only placeholder data - if (isLoadingDid || isLoadingProfile || isPlaceholderProfile) { + if (isLoadingDid || isLoadingProfile) { return ( - + ) } @@ -114,6 +115,7 @@ export function ProfileScreen({route}: Props) { ) @@ -132,12 +134,14 @@ export function ProfileScreen({route}: Props) { function ProfileScreenLoaded({ profile: profileUnshadowed, + isPlaceholderProfile, moderationOpts, hideBackButton, }: { profile: AppBskyActorDefs.ProfileViewDetailed moderationOpts: ModerationOpts hideBackButton: boolean + isPlaceholderProfile: boolean }) { const profile = useProfileShadow(profileUnshadowed) const {hasSession, currentAccount} = useSession() @@ -157,6 +161,10 @@ function ProfileScreenLoaded({ useSetTitle(combinedDisplayName(profile)) + const description = profile.description ?? '' + const hasDescription = description !== '' + const [descriptionRT, isResolvingDescriptionRT] = useRichText(description) + const showPlaceholder = isPlaceholderProfile || isResolvingDescriptionRT const moderation = useMemo( () => moderateProfile(profile, moderationOpts), [profile, moderationOpts], @@ -270,11 +278,20 @@ function ProfileScreenLoaded({ return ( ) - }, [profile, moderationOpts, hideBackButton]) + }, [ + profile, + descriptionRT, + hasDescription, + moderationOpts, + hideBackButton, + showPlaceholder, + ]) return ( new RichTextAPI({text})) + const [resolvedRT, setResolvedRT] = React.useState(null) + if (text !== prevText) { + setPrevText(text) + setRawRT(new RichTextAPI({text})) + setResolvedRT(null) + // This will queue an immediate re-render + } + React.useEffect(() => { + let ignore = false + async function resolveRTFacets() { + // new each time + const resolvedRT = new RichTextAPI({text}) + await resolvedRT.detectFacets(getAgent()) + if (!ignore) { + setResolvedRT(resolvedRT) + } + } + resolveRTFacets() + return () => { + ignore = true + } + }, [text]) + const isResolving = resolvedRT === null + return [resolvedRT ?? rawRT, isResolving] +} + const styles = StyleSheet.create({ container: { flexDirection: 'column', -- cgit 1.4.1