diff options
author | dan <dan.abramov@gmail.com> | 2023-10-13 20:10:15 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-10-13 20:10:15 +0100 |
commit | f447eaa6692c46921bf1124e2cfe2f030f0cc08d (patch) | |
tree | 3f903f2b9fbebdefe2a7cfbbaed52b274707ca4c /src | |
parent | d5ccbd76d5ffc9280f0109138f608b94bee0aadf (diff) | |
download | voidsky-f447eaa6692c46921bf1124e2cfe2f030f0cc08d.tar.zst |
Fix profile preview jump (#1693)
* Add top inset for profile preview to match target screen * Avoid flicker by waiting for profile screen navigation * Fix glimmer to align with the content * A more reliable (but non-scientific) fix for the flash * Lower the timeout
Diffstat (limited to 'src')
-rw-r--r-- | src/Navigation.tsx | 16 | ||||
-rw-r--r-- | src/view/com/modals/Modal.tsx | 20 | ||||
-rw-r--r-- | src/view/com/modals/ProfilePreview.tsx | 11 | ||||
-rw-r--r-- | src/view/com/profile/ProfileHeader.tsx | 4 |
4 files changed, 33 insertions, 18 deletions
diff --git a/src/Navigation.tsx b/src/Navigation.tsx index 97612c9ec..e1d5e76aa 100644 --- a/src/Navigation.tsx +++ b/src/Navigation.tsx @@ -483,9 +483,21 @@ function navigate<K extends keyof AllNavigatorParams>( params?: AllNavigatorParams[K], ) { if (navigationRef.isReady()) { - // @ts-ignore I dont know what would make typescript happy but I have a life -prf - navigationRef.navigate(name, params) + return Promise.race([ + new Promise<void>(resolve => { + const handler = () => { + resolve() + navigationRef.removeListener('state', handler) + } + navigationRef.addListener('state', handler) + + // @ts-ignore I dont know what would make typescript happy but I have a life -prf + navigationRef.navigate(name, params) + }), + timeout(1e3), + ]) } + return Promise.resolve() } function resetToTab(tabName: 'HomeTab' | 'SearchTab' | 'NotificationsTab') { diff --git a/src/view/com/modals/Modal.tsx b/src/view/com/modals/Modal.tsx index 4f3f424a3..1fe1299d7 100644 --- a/src/view/com/modals/Modal.tsx +++ b/src/view/com/modals/Modal.tsx @@ -1,11 +1,12 @@ import React, {useRef, useEffect} from 'react' import {StyleSheet} from 'react-native' -import {SafeAreaView} from 'react-native-safe-area-context' +import {SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context' import {observer} from 'mobx-react-lite' import BottomSheet from '@gorhom/bottom-sheet' import {useStores} from 'state/index' import {createCustomBackdrop} from '../util/BottomSheetCustomBackdrop' import {usePalette} from 'lib/hooks/usePalette' +import {timeout} from 'lib/async/timeout' import {navigate} from '../../../Navigation' import once from 'lodash.once' @@ -36,11 +37,13 @@ import * as SwitchAccountModal from './SwitchAccount' import * as LinkWarningModal from './LinkWarning' const DEFAULT_SNAPPOINTS = ['90%'] +const HANDLE_HEIGHT = 24 export const ModalsContainer = observer(function ModalsContainer() { const store = useStores() const bottomSheetRef = useRef<BottomSheet>(null) const pal = usePalette('default') + const safeAreaInsets = useSafeAreaInsets() const activeModal = store.shell.activeModals[store.shell.activeModals.length - 1] @@ -53,12 +56,16 @@ export const ModalsContainer = observer(function ModalsContainer() { navigateOnce('Profile', {name: activeModal.did}) } } - const onBottomSheetChange = (snapPoint: number) => { + const onBottomSheetChange = async (snapPoint: number) => { if (snapPoint === -1) { store.shell.closeModal() } else if (activeModal?.name === 'profile-preview' && snapPoint === 1) { - // ensure we navigate to Profile and close the modal - navigateOnce('Profile', {name: activeModal.did}) + await navigateOnce('Profile', {name: activeModal.did}) + // There is no particular callback for when the view has actually been presented. + // This delay gives us a decent chance the navigation has flushed *and* images have loaded. + // It's acceptable because the data is already being fetched + it usually takes longer anyway. + // TODO: Figure out why avatar/cover don't always show instantly from cache. + await timeout(200) store.shell.closeModal() } } @@ -75,6 +82,7 @@ export const ModalsContainer = observer(function ModalsContainer() { } }, [store.shell.isModalActive, bottomSheetRef, activeModal?.name]) + let needsSafeTopInset = false let snapPoints: (string | number)[] = DEFAULT_SNAPPOINTS let element if (activeModal?.name === 'confirm') { @@ -86,6 +94,7 @@ export const ModalsContainer = observer(function ModalsContainer() { } else if (activeModal?.name === 'profile-preview') { snapPoints = ProfilePreviewModal.snapPoints element = <ProfilePreviewModal.Component {...activeModal} /> + needsSafeTopInset = true // Need to align with the target profile screen. } else if (activeModal?.name === 'server-input') { snapPoints = ServerInputModal.snapPoints element = <ServerInputModal.Component {...activeModal} /> @@ -164,10 +173,13 @@ export const ModalsContainer = observer(function ModalsContainer() { ) } + const topInset = needsSafeTopInset ? safeAreaInsets.top - HANDLE_HEIGHT : 0 return ( <BottomSheet ref={bottomSheetRef} snapPoints={snapPoints} + topInset={topInset} + handleHeight={HANDLE_HEIGHT} index={store.shell.isModalActive ? 0 : -1} enablePanDownToClose android_keyboardInputMode="adjustResize" diff --git a/src/view/com/modals/ProfilePreview.tsx b/src/view/com/modals/ProfilePreview.tsx index 225a3972b..dad02aa5e 100644 --- a/src/view/com/modals/ProfilePreview.tsx +++ b/src/view/com/modals/ProfilePreview.tsx @@ -9,7 +9,6 @@ import {useAnalytics} from 'lib/analytics/analytics' import {ProfileHeader} from '../profile/ProfileHeader' import {InfoCircleIcon} from 'lib/icons' import {useNavigationState} from '@react-navigation/native' -import {isIOS} from 'platform/detection' import {s} from 'lib/styles' export const snapPoints = [520, '100%'] @@ -36,11 +35,7 @@ export const Component = observer(function ProfilePreviewImpl({ return ( <View testID="profilePreview" style={[pal.view, s.flex1]}> - <View - style={[ - styles.headerWrapper, - isLoading && isIOS && styles.headerPositionAdjust, - ]}> + <View style={[styles.headerWrapper]}> <ProfileHeader view={model} hideBackButton @@ -70,10 +65,6 @@ const styles = StyleSheet.create({ headerWrapper: { height: 440, }, - headerPositionAdjust: { - // HACK align the header for the profilescreen transition -prf - paddingTop: 23, - }, hintWrapper: { height: 80, }, diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx index baf95af6c..df19ecad5 100644 --- a/src/view/com/profile/ProfileHeader.tsx +++ b/src/view/com/profile/ProfileHeader.tsx @@ -60,14 +60,14 @@ export const ProfileHeader = observer(function ProfileHeaderImpl({ if (!view || !view.hasLoaded) { return ( <View style={pal.view}> - <LoadingPlaceholder width="100%" height={120} /> + <LoadingPlaceholder width="100%" height={153} /> <View style={[pal.view, {borderColor: pal.colors.background}, styles.avi]}> <LoadingPlaceholder width={80} height={80} style={styles.br40} /> </View> <View style={styles.content}> <View style={[styles.buttonsLine]}> - <LoadingPlaceholder width={100} height={31} style={styles.br50} /> + <LoadingPlaceholder width={167} height={31} style={styles.br50} /> </View> <View> <Text type="title-2xl" style={[pal.text, styles.title]}> |