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 timeoutzio/stable
parent
d5ccbd76d5
commit
f447eaa669
|
@ -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') {
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
|
|
|
@ -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]}>
|
||||
|
|
Loading…
Reference in New Issue