Fix jump when toggling suggestions (#2090)

zio/stable
dan 2023-12-05 17:13:09 +00:00 committed by GitHub
parent 37d94ca0e3
commit ed5a97d0fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 74 additions and 100 deletions

View File

@ -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],

View File

@ -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)
}
}}
/> />
)} )}

View File

@ -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>
) )
} }