Fix jump when toggling suggestions (#2090)
parent
37d94ca0e3
commit
ed5a97d0fa
|
@ -71,7 +71,8 @@ export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>(
|
||||||
(evt: LayoutChangeEvent) => {
|
(evt: LayoutChangeEvent) => {
|
||||||
const height = evt.nativeEvent.layout.height
|
const height = evt.nativeEvent.layout.height
|
||||||
if (height > 0) {
|
if (height > 0) {
|
||||||
setTabBarHeight(height)
|
// The rounding is necessary to prevent jumps on iOS
|
||||||
|
setTabBarHeight(Math.round(height))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[setTabBarHeight],
|
[setTabBarHeight],
|
||||||
|
@ -80,7 +81,8 @@ export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>(
|
||||||
(evt: LayoutChangeEvent) => {
|
(evt: LayoutChangeEvent) => {
|
||||||
const height = evt.nativeEvent.layout.height
|
const height = evt.nativeEvent.layout.height
|
||||||
if (height > 0) {
|
if (height > 0) {
|
||||||
setHeaderOnlyHeight(height)
|
// The rounding is necessary to prevent jumps on iOS
|
||||||
|
setHeaderOnlyHeight(Math.round(height))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[setHeaderOnlyHeight],
|
[setHeaderOnlyHeight],
|
||||||
|
|
|
@ -620,11 +620,17 @@ let ProfileHeaderLoaded = ({
|
||||||
<ProfileHeaderAlerts moderation={moderation} />
|
<ProfileHeaderAlerts moderation={moderation} />
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{!isProfilePreview && (
|
{!isProfilePreview && showSuggestedFollows && (
|
||||||
<ProfileHeaderSuggestedFollows
|
<ProfileHeaderSuggestedFollows
|
||||||
actorDid={profile.did}
|
actorDid={profile.did}
|
||||||
active={showSuggestedFollows}
|
requestDismiss={() => {
|
||||||
requestDismiss={() => setShowSuggestedFollows(!showSuggestedFollows)}
|
if (showSuggestedFollows) {
|
||||||
|
setShowSuggestedFollows(false)
|
||||||
|
} else {
|
||||||
|
track('ProfileHeader:SuggestedFollowsOpened')
|
||||||
|
setShowSuggestedFollows(true)
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {View, StyleSheet, Pressable, ScrollView} from 'react-native'
|
import {View, StyleSheet, Pressable, ScrollView} from 'react-native'
|
||||||
import Animated, {
|
|
||||||
useSharedValue,
|
|
||||||
withTiming,
|
|
||||||
useAnimatedStyle,
|
|
||||||
Easing,
|
|
||||||
} from 'react-native-reanimated'
|
|
||||||
import {AppBskyActorDefs, moderateProfile} from '@atproto/api'
|
import {AppBskyActorDefs, moderateProfile} from '@atproto/api'
|
||||||
import {
|
import {
|
||||||
FontAwesomeIcon,
|
FontAwesomeIcon,
|
||||||
|
@ -34,112 +28,84 @@ const TOTAL_HEIGHT = 250
|
||||||
|
|
||||||
export function ProfileHeaderSuggestedFollows({
|
export function ProfileHeaderSuggestedFollows({
|
||||||
actorDid,
|
actorDid,
|
||||||
active,
|
|
||||||
requestDismiss,
|
requestDismiss,
|
||||||
}: {
|
}: {
|
||||||
actorDid: string
|
actorDid: string
|
||||||
active: boolean
|
|
||||||
requestDismiss: () => void
|
requestDismiss: () => void
|
||||||
}) {
|
}) {
|
||||||
const {track} = useAnalytics()
|
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const animatedHeight = useSharedValue(0)
|
|
||||||
const animatedStyles = useAnimatedStyle(() => ({
|
|
||||||
opacity: animatedHeight.value / TOTAL_HEIGHT,
|
|
||||||
height: animatedHeight.value,
|
|
||||||
}))
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (active) {
|
|
||||||
track('ProfileHeader:SuggestedFollowsOpened')
|
|
||||||
|
|
||||||
animatedHeight.value = withTiming(TOTAL_HEIGHT, {
|
|
||||||
duration: 500,
|
|
||||||
easing: Easing.inOut(Easing.exp),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
animatedHeight.value = withTiming(0, {
|
|
||||||
duration: 500,
|
|
||||||
easing: Easing.inOut(Easing.exp),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}, [active, animatedHeight, track])
|
|
||||||
|
|
||||||
const {isLoading, data} = useSuggestedFollowsByActorQuery({
|
const {isLoading, data} = useSuggestedFollowsByActorQuery({
|
||||||
did: actorDid,
|
did: actorDid,
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Animated.View
|
<View
|
||||||
pointerEvents="box-none"
|
style={{paddingVertical: OUTER_PADDING, height: TOTAL_HEIGHT}}
|
||||||
style={[{overflow: 'hidden', opacity: 0}, animatedStyles]}>
|
pointerEvents="box-none">
|
||||||
<View style={{paddingVertical: OUTER_PADDING}} pointerEvents="box-none">
|
<View
|
||||||
|
pointerEvents="box-none"
|
||||||
|
style={{
|
||||||
|
backgroundColor: pal.viewLight.backgroundColor,
|
||||||
|
height: '100%',
|
||||||
|
paddingTop: INNER_PADDING / 2,
|
||||||
|
}}>
|
||||||
<View
|
<View
|
||||||
pointerEvents="box-none"
|
pointerEvents="box-none"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: pal.viewLight.backgroundColor,
|
flexDirection: 'row',
|
||||||
height: '100%',
|
justifyContent: 'space-between',
|
||||||
paddingTop: INNER_PADDING / 2,
|
alignItems: 'center',
|
||||||
|
paddingTop: 4,
|
||||||
|
paddingBottom: INNER_PADDING / 2,
|
||||||
|
paddingLeft: INNER_PADDING,
|
||||||
|
paddingRight: INNER_PADDING / 2,
|
||||||
}}>
|
}}>
|
||||||
<View
|
<Text type="sm-bold" style={[pal.textLight]}>
|
||||||
pointerEvents="box-none"
|
Suggested for you
|
||||||
style={{
|
</Text>
|
||||||
flexDirection: 'row',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
alignItems: 'center',
|
|
||||||
paddingTop: 4,
|
|
||||||
paddingBottom: INNER_PADDING / 2,
|
|
||||||
paddingLeft: INNER_PADDING,
|
|
||||||
paddingRight: INNER_PADDING / 2,
|
|
||||||
}}>
|
|
||||||
<Text type="sm-bold" style={[pal.textLight]}>
|
|
||||||
Suggested for you
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<Pressable
|
<Pressable
|
||||||
accessibilityRole="button"
|
accessibilityRole="button"
|
||||||
onPress={requestDismiss}
|
onPress={requestDismiss}
|
||||||
hitSlop={10}
|
hitSlop={10}
|
||||||
style={{padding: INNER_PADDING / 2}}>
|
style={{padding: INNER_PADDING / 2}}>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon="x"
|
icon="x"
|
||||||
size={12}
|
size={12}
|
||||||
style={pal.textLight as FontAwesomeIconStyle}
|
style={pal.textLight as FontAwesomeIconStyle}
|
||||||
/>
|
/>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
</View>
|
|
||||||
|
|
||||||
<ScrollView
|
|
||||||
horizontal={true}
|
|
||||||
showsHorizontalScrollIndicator={isWeb}
|
|
||||||
persistentScrollbar={true}
|
|
||||||
scrollIndicatorInsets={{bottom: 0}}
|
|
||||||
scrollEnabled={true}
|
|
||||||
contentContainerStyle={{
|
|
||||||
alignItems: 'flex-start',
|
|
||||||
paddingLeft: INNER_PADDING / 2,
|
|
||||||
paddingBottom: INNER_PADDING,
|
|
||||||
}}>
|
|
||||||
{isLoading ? (
|
|
||||||
<>
|
|
||||||
<SuggestedFollowSkeleton />
|
|
||||||
<SuggestedFollowSkeleton />
|
|
||||||
<SuggestedFollowSkeleton />
|
|
||||||
<SuggestedFollowSkeleton />
|
|
||||||
<SuggestedFollowSkeleton />
|
|
||||||
<SuggestedFollowSkeleton />
|
|
||||||
</>
|
|
||||||
) : data ? (
|
|
||||||
data.suggestions.map(profile => (
|
|
||||||
<SuggestedFollow key={profile.did} profile={profile} />
|
|
||||||
))
|
|
||||||
) : (
|
|
||||||
<View />
|
|
||||||
)}
|
|
||||||
</ScrollView>
|
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
horizontal={true}
|
||||||
|
showsHorizontalScrollIndicator={isWeb}
|
||||||
|
persistentScrollbar={true}
|
||||||
|
scrollIndicatorInsets={{bottom: 0}}
|
||||||
|
scrollEnabled={true}
|
||||||
|
contentContainerStyle={{
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
paddingLeft: INNER_PADDING / 2,
|
||||||
|
paddingBottom: INNER_PADDING,
|
||||||
|
}}>
|
||||||
|
{isLoading ? (
|
||||||
|
<>
|
||||||
|
<SuggestedFollowSkeleton />
|
||||||
|
<SuggestedFollowSkeleton />
|
||||||
|
<SuggestedFollowSkeleton />
|
||||||
|
<SuggestedFollowSkeleton />
|
||||||
|
<SuggestedFollowSkeleton />
|
||||||
|
<SuggestedFollowSkeleton />
|
||||||
|
</>
|
||||||
|
) : data ? (
|
||||||
|
data.suggestions.map(profile => (
|
||||||
|
<SuggestedFollow key={profile.did} profile={profile} />
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<View />
|
||||||
|
)}
|
||||||
|
</ScrollView>
|
||||||
</View>
|
</View>
|
||||||
</Animated.View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue