scroll animation on logo
This commit is contained in:
@@ -1,13 +1,17 @@
|
||||
import React from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {NativeScrollEvent, View} from 'react-native'
|
||||
import {AppBskyActorDefs} from '@atproto/api'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {NavigationProp, useNavigation} from '@react-navigation/native'
|
||||
import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {useAnalytics} from '#/lib/analytics/analytics'
|
||||
import {ComposeIcon2} from '#/lib/icons'
|
||||
import {getRootNavigation, getTabState, TabState} from '#/lib/routes/helpers'
|
||||
import {AllNavigatorParams} from '#/lib/routes/types'
|
||||
import {logEvent} from '#/lib/statsig/statsig'
|
||||
import {s} from '#/lib/styles'
|
||||
import {isNative} from '#/platform/detection'
|
||||
import {listenSoftReset} from '#/state/events'
|
||||
import {FeedFeedbackProvider, useFeedFeedback} from '#/state/feed-feedback'
|
||||
@@ -17,10 +21,6 @@ import {truncateAndInvalidate} from '#/state/queries/util'
|
||||
import {useSession} from '#/state/session'
|
||||
import {useSetMinimalShellMode} from '#/state/shell'
|
||||
import {useComposerControls} from '#/state/shell/composer'
|
||||
import {useAnalytics} from 'lib/analytics/analytics'
|
||||
import {ComposeIcon2} from 'lib/icons'
|
||||
import {AllNavigatorParams} from 'lib/routes/types'
|
||||
import {s} from 'lib/styles'
|
||||
import {useHeaderOffset} from '#/components/hooks/useHeaderOffset'
|
||||
import {Feed} from '../posts/Feed'
|
||||
import {FAB} from '../util/fab/FAB'
|
||||
@@ -38,6 +38,7 @@ export function FeedPage({
|
||||
renderEmptyState,
|
||||
renderEndOfFeed,
|
||||
savedFeedConfig,
|
||||
onScroll,
|
||||
}: {
|
||||
testID?: string
|
||||
feed: FeedDescriptor
|
||||
@@ -46,6 +47,7 @@ export function FeedPage({
|
||||
renderEmptyState: () => JSX.Element
|
||||
renderEndOfFeed?: () => JSX.Element
|
||||
savedFeedConfig?: AppBskyActorDefs.SavedFeed
|
||||
onScroll: (e: NativeScrollEvent) => void
|
||||
}) {
|
||||
const {hasSession} = useSession()
|
||||
const {_} = useLingui()
|
||||
@@ -111,7 +113,7 @@ export function FeedPage({
|
||||
|
||||
return (
|
||||
<View testID={testID} style={s.h100pct}>
|
||||
<MainScrollProvider>
|
||||
<MainScrollProvider onScroll={onScroll}>
|
||||
<FeedFeedbackProvider value={feedFeedback}>
|
||||
<Feed
|
||||
testID={testID ? `${testID}-feed` : undefined}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import React from 'react'
|
||||
import {SharedValue} from 'react-native-reanimated'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
import {NavigationProp} from '#/lib/routes/types'
|
||||
import {FeedSourceInfo} from '#/state/queries/feed'
|
||||
import {useSession} from '#/state/session'
|
||||
import {NavigationProp} from 'lib/routes/types'
|
||||
import {RenderTabBarFnProps} from 'view/com/pager/Pager'
|
||||
import {RenderTabBarFnProps} from '#/view/com/pager/Pager'
|
||||
import {TabBar} from '../pager/TabBar'
|
||||
import {HomeHeaderLayout} from './HomeHeaderLayout'
|
||||
|
||||
@@ -14,9 +15,10 @@ export function HomeHeader(
|
||||
testID?: string
|
||||
onPressSelected: () => void
|
||||
feeds: FeedSourceInfo[]
|
||||
scrollY: SharedValue<number>
|
||||
},
|
||||
) {
|
||||
const {feeds} = props
|
||||
const {feeds, scrollY} = props
|
||||
const {hasSession} = useSession()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
const pal = usePalette('default')
|
||||
@@ -53,7 +55,7 @@ export function HomeHeader(
|
||||
)
|
||||
|
||||
return (
|
||||
<HomeHeaderLayout tabBarAnchor={props.tabBarAnchor}>
|
||||
<HomeHeaderLayout tabBarAnchor={props.tabBarAnchor} scrollY={scrollY}>
|
||||
<TabBar
|
||||
key={items.join(',')}
|
||||
onPressSelected={props.onPressSelected}
|
||||
|
||||
@@ -13,10 +13,10 @@ import Animated, {
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {useMinimalShellHeaderTransform} from '#/lib/hooks/useMinimalShellTransform'
|
||||
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
||||
import {useSession} from '#/state/session'
|
||||
import {useShellLayout} from '#/state/shell/shell-layout'
|
||||
import {useMinimalShellHeaderTransform} from 'lib/hooks/useMinimalShellTransform'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
// import {Logo} from '#/view/icons/Logo'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {Icon, Trigger} from '#/components/dialogs/nuxs/TenMillion/Trigger'
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
import React from 'react'
|
||||
import {StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||
import React, {useState} from 'react'
|
||||
import {
|
||||
ActivityIndicator,
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} from 'react-native'
|
||||
import Animated, {
|
||||
Extrapolation,
|
||||
interpolate,
|
||||
LayoutAnimationConfig,
|
||||
SharedValue,
|
||||
useAnimatedStyle,
|
||||
useReducedMotion,
|
||||
useSharedValue,
|
||||
@@ -9,22 +18,23 @@ import Animated, {
|
||||
withSequence,
|
||||
withSpring,
|
||||
withTiming,
|
||||
ZoomIn,
|
||||
ZoomOut,
|
||||
} from 'react-native-reanimated'
|
||||
import {useSafeAreaFrame} from 'react-native-safe-area-context'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {HITSLOP_10} from '#/lib/constants'
|
||||
import {useMinimalShellHeaderTransform} from '#/lib/hooks/useMinimalShellTransform'
|
||||
import {isWeb} from '#/platform/detection'
|
||||
import {useSession} from '#/state/session'
|
||||
import {useSetDrawerOpen} from '#/state/shell/drawer-open'
|
||||
import {useShellLayout} from '#/state/shell/shell-layout'
|
||||
import {HITSLOP_10} from 'lib/constants'
|
||||
import {useMinimalShellHeaderTransform} from 'lib/hooks/useMinimalShellTransform'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {isWeb} from 'platform/detection'
|
||||
// import {Logo} from '#/view/icons/Logo'
|
||||
import {atoms} from '#/alf'
|
||||
import {useTheme} from '#/alf'
|
||||
import {atoms as a} from '#/alf'
|
||||
import {atoms as a, native, useTheme} from '#/alf'
|
||||
import {Icon, Trigger} from '#/components/dialogs/nuxs/TenMillion/Trigger'
|
||||
import {useOverscrolled} from '#/components/hooks/useOverscrolled'
|
||||
import {ColorPalette_Stroke2_Corner0_Rounded as ColorPalette} from '#/components/icons/ColorPalette'
|
||||
import {Hashtag_Stroke2_Corner0_Rounded as FeedsIcon} from '#/components/icons/Hashtag'
|
||||
import {Menu_Stroke2_Corner0_Rounded as Menu} from '#/components/icons/Menu'
|
||||
@@ -33,17 +43,20 @@ import {IS_DEV} from '#/env'
|
||||
|
||||
export function HomeHeaderLayoutMobile({
|
||||
children,
|
||||
scrollY,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
tabBarAnchor: JSX.Element | null | undefined
|
||||
scrollY?: SharedValue<number>
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const pal = usePalette('default')
|
||||
const {_} = useLingui()
|
||||
const setDrawerOpen = useSetDrawerOpen()
|
||||
const {headerHeight} = useShellLayout()
|
||||
const {height: frameHeight} = useSafeAreaFrame()
|
||||
const headerMinimalShellTransform = useMinimalShellHeaderTransform()
|
||||
const {hasSession} = useSession()
|
||||
const showSpinner = useShowSpinner({scrollY})
|
||||
|
||||
const onPressAvi = React.useCallback(() => {
|
||||
setDrawerOpen(true)
|
||||
@@ -78,7 +91,34 @@ export function HomeHeaderLayoutMobile({
|
||||
)
|
||||
}, [rotate, reducedMotion])
|
||||
|
||||
const animatedStyle = useAnimatedStyle(() => ({
|
||||
const animatedContainerStyle = useAnimatedStyle(() => ({
|
||||
transform: [
|
||||
{
|
||||
translateY: isWeb
|
||||
? 0
|
||||
: interpolate(
|
||||
scrollY?.value ?? -headerHeight.value,
|
||||
[-headerHeight.value, 0],
|
||||
[headerHeight.value, 0],
|
||||
{extrapolateRight: Extrapolation.CLAMP},
|
||||
),
|
||||
},
|
||||
],
|
||||
}))
|
||||
|
||||
const animatedLogoContainerStyle = useAnimatedStyle(() => ({
|
||||
transform: [
|
||||
{
|
||||
translateY: isWeb
|
||||
? 0
|
||||
: interpolate(scrollY?.value ?? 0, [-2, 0], [-1, 0], {
|
||||
extrapolateRight: Extrapolation.CLAMP,
|
||||
}),
|
||||
},
|
||||
],
|
||||
}))
|
||||
|
||||
const animatedJiggleStyle = useAnimatedStyle(() => ({
|
||||
transform: [
|
||||
{
|
||||
rotateZ: `${rotate.value}deg`,
|
||||
@@ -86,78 +126,125 @@ export function HomeHeaderLayoutMobile({
|
||||
],
|
||||
}))
|
||||
|
||||
console.log(headerHeight.value)
|
||||
|
||||
return (
|
||||
<Animated.View
|
||||
style={[pal.view, pal.border, styles.tabBar, headerMinimalShellTransform]}
|
||||
onLayout={e => {
|
||||
headerHeight.value = e.nativeEvent.layout.height
|
||||
}}>
|
||||
<View style={[pal.view, styles.topBar]}>
|
||||
<View style={[pal.view, {width: 100}]}>
|
||||
<TouchableOpacity
|
||||
testID="viewHeaderDrawerBtn"
|
||||
onPress={onPressAvi}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={_(msg`Open navigation`)}
|
||||
accessibilityHint={_(
|
||||
msg`Access profile and other navigation links`,
|
||||
)}
|
||||
hitSlop={HITSLOP_10}>
|
||||
<Menu size="lg" fill={t.atoms.text_contrast_medium.color} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<Animated.View style={animatedStyle}>
|
||||
<Trigger>
|
||||
{ctx => (
|
||||
<Icon
|
||||
width={28}
|
||||
style={{
|
||||
opacity: ctx.pressed ? 0.8 : 1,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Trigger>
|
||||
{/* <Logo width={30} /> */}
|
||||
</Animated.View>
|
||||
pointerEvents="box-none"
|
||||
style={[styles.tabBar, animatedContainerStyle]}>
|
||||
{native(
|
||||
<View
|
||||
style={[
|
||||
atoms.flex_row,
|
||||
atoms.justify_end,
|
||||
atoms.align_center,
|
||||
atoms.gap_md,
|
||||
pal.view,
|
||||
{width: 100},
|
||||
]}>
|
||||
{IS_DEV && (
|
||||
<>
|
||||
<Link label="View storybook" to="/sys/debug">
|
||||
<ColorPalette size="md" />
|
||||
a.absolute,
|
||||
{height: frameHeight},
|
||||
{bottom: '100%', left: 0, right: 0},
|
||||
t.atoms.bg,
|
||||
]}
|
||||
/>,
|
||||
)}
|
||||
<Animated.View
|
||||
style={[
|
||||
t.atoms.bg,
|
||||
t.atoms.border_contrast_medium,
|
||||
headerMinimalShellTransform,
|
||||
]}
|
||||
onLayout={e => {
|
||||
headerHeight.value = e.nativeEvent.layout.height
|
||||
}}>
|
||||
<View style={[styles.topBar]}>
|
||||
<View style={[{width: 100}]}>
|
||||
<TouchableOpacity
|
||||
testID="viewHeaderDrawerBtn"
|
||||
onPress={onPressAvi}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={_(msg`Open navigation`)}
|
||||
accessibilityHint={_(
|
||||
msg`Access profile and other navigation links`,
|
||||
)}
|
||||
hitSlop={HITSLOP_10}>
|
||||
<Menu size="lg" fill={t.atoms.text_contrast_medium.color} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<Animated.View style={[animatedLogoContainerStyle]}>
|
||||
<LayoutAnimationConfig skipEntering skipExiting>
|
||||
{showSpinner ? (
|
||||
<Animated.View
|
||||
key={1}
|
||||
entering={ZoomIn.delay(200)}
|
||||
exiting={ZoomOut}
|
||||
pointerEvents="none"
|
||||
style={[a.absolute, a.inset_0, a.align_center]}>
|
||||
<ActivityIndicator
|
||||
size="small"
|
||||
color={t.atoms.text_contrast_low.color}
|
||||
/>
|
||||
</Animated.View>
|
||||
) : (
|
||||
<Animated.View
|
||||
key={2}
|
||||
entering={ZoomIn.delay(300)}
|
||||
exiting={ZoomOut}
|
||||
style={[a.absolute, a.inset_0, a.align_center]}>
|
||||
<Animated.View style={[animatedJiggleStyle]}>
|
||||
<Trigger>
|
||||
{ctx => (
|
||||
<Icon
|
||||
width={28}
|
||||
style={{
|
||||
opacity: ctx.pressed ? 0.8 : 1,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Trigger>
|
||||
</Animated.View>
|
||||
{/* <Logo width={30} /> */}
|
||||
</Animated.View>
|
||||
)}
|
||||
</LayoutAnimationConfig>
|
||||
</Animated.View>
|
||||
<View
|
||||
style={[
|
||||
a.flex_row,
|
||||
a.justify_end,
|
||||
a.align_center,
|
||||
a.gap_md,
|
||||
t.atoms.bg,
|
||||
{width: 100},
|
||||
]}>
|
||||
{IS_DEV && (
|
||||
<>
|
||||
<Link label="View storybook" to="/sys/debug">
|
||||
<ColorPalette size="md" />
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
{hasSession && (
|
||||
<Link
|
||||
testID="viewHeaderHomeFeedPrefsBtn"
|
||||
to="/feeds"
|
||||
hitSlop={HITSLOP_10}
|
||||
label={_(msg`View your feeds and explore more`)}
|
||||
size="small"
|
||||
variant="ghost"
|
||||
color="secondary"
|
||||
shape="square"
|
||||
style={[
|
||||
a.justify_center,
|
||||
{
|
||||
marginTop: 2,
|
||||
marginRight: -6,
|
||||
},
|
||||
]}>
|
||||
<FeedsIcon
|
||||
size="lg"
|
||||
fill={t.atoms.text_contrast_medium.color}
|
||||
/>
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
{hasSession && (
|
||||
<Link
|
||||
testID="viewHeaderHomeFeedPrefsBtn"
|
||||
to="/feeds"
|
||||
hitSlop={HITSLOP_10}
|
||||
label={_(msg`View your feeds and explore more`)}
|
||||
size="small"
|
||||
variant="ghost"
|
||||
color="secondary"
|
||||
shape="square"
|
||||
style={[
|
||||
a.justify_center,
|
||||
{
|
||||
marginTop: 2,
|
||||
marginRight: -6,
|
||||
},
|
||||
]}>
|
||||
<FeedsIcon size="lg" fill={t.atoms.text_contrast_medium.color} />
|
||||
</Link>
|
||||
)}
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
{children}
|
||||
{children}
|
||||
</Animated.View>
|
||||
</Animated.View>
|
||||
)
|
||||
}
|
||||
@@ -170,7 +257,6 @@ const styles = StyleSheet.create({
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: 0,
|
||||
flexDirection: 'column',
|
||||
},
|
||||
topBar: {
|
||||
flexDirection: 'row',
|
||||
@@ -185,3 +271,25 @@ const styles = StyleSheet.create({
|
||||
fontSize: 21,
|
||||
},
|
||||
})
|
||||
|
||||
function useShowSpinner({scrollY}: {scrollY?: SharedValue<number>}) {
|
||||
console.log(scrollY?.value)
|
||||
const isOverscrolled = useOverscrolled({scrollY, threshold: -15})
|
||||
const isSignificantlyOverscrolled = useOverscrolled({scrollY, threshold: -65})
|
||||
const [
|
||||
hasBeenSignificantlyOverscrolled,
|
||||
setHasBeenSignificantlyOverscrolled,
|
||||
] = useState(isSignificantlyOverscrolled)
|
||||
|
||||
if (isSignificantlyOverscrolled && !hasBeenSignificantlyOverscrolled) {
|
||||
setHasBeenSignificantlyOverscrolled(true)
|
||||
} else if (
|
||||
!isOverscrolled &&
|
||||
!isSignificantlyOverscrolled &&
|
||||
hasBeenSignificantlyOverscrolled
|
||||
) {
|
||||
setHasBeenSignificantlyOverscrolled(false)
|
||||
}
|
||||
|
||||
return isOverscrolled && hasBeenSignificantlyOverscrolled
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@ import {
|
||||
import EventEmitter from 'eventemitter3'
|
||||
|
||||
import {ScrollProvider} from '#/lib/ScrollContext'
|
||||
import {isNative, isWeb} from '#/platform/detection'
|
||||
import {useMinimalShellMode} from '#/state/shell'
|
||||
import {useShellLayout} from '#/state/shell/shell-layout'
|
||||
import {isNative, isWeb} from 'platform/detection'
|
||||
|
||||
const WEB_HIDE_SHELL_THRESHOLD = 200
|
||||
|
||||
@@ -20,7 +20,13 @@ function clamp(num: number, min: number, max: number) {
|
||||
return Math.min(Math.max(num, min), max)
|
||||
}
|
||||
|
||||
export function MainScrollProvider({children}: {children: React.ReactNode}) {
|
||||
export function MainScrollProvider({
|
||||
children,
|
||||
onScroll: onScrollProp,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
onScroll?: (e: NativeScrollEvent) => void
|
||||
}) {
|
||||
const {headerHeight} = useShellLayout()
|
||||
const {headerMode} = useMinimalShellMode()
|
||||
const startDragOffset = useSharedValue<number | null>(null)
|
||||
@@ -112,6 +118,8 @@ export function MainScrollProvider({children}: {children: React.ReactNode}) {
|
||||
(e: NativeScrollEvent) => {
|
||||
'worklet'
|
||||
if (isNative) {
|
||||
if (onScrollProp) onScrollProp(e)
|
||||
|
||||
if (startDragOffset.value === null || startMode.value === null) {
|
||||
if (
|
||||
headerMode.value !== 0 &&
|
||||
@@ -164,6 +172,7 @@ export function MainScrollProvider({children}: {children: React.ReactNode}) {
|
||||
startDragOffset,
|
||||
startMode,
|
||||
didJustRestoreScroll,
|
||||
onScrollProp,
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
+34
-11
@@ -1,10 +1,22 @@
|
||||
import React from 'react'
|
||||
import {ActivityIndicator, StyleSheet, View} from 'react-native'
|
||||
import {
|
||||
ActivityIndicator,
|
||||
NativeScrollEvent,
|
||||
StyleSheet,
|
||||
View,
|
||||
} from 'react-native'
|
||||
import {useSharedValue} from 'react-native-reanimated'
|
||||
import {useFocusEffect} from '@react-navigation/native'
|
||||
|
||||
import {PROD_DEFAULT_FEED} from '#/lib/constants'
|
||||
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
||||
import {useOTAUpdates} from '#/lib/hooks/useOTAUpdates'
|
||||
import {useSetTitle} from '#/lib/hooks/useSetTitle'
|
||||
import {useRequestNotificationsPermission} from '#/lib/notifications/notifications'
|
||||
import {
|
||||
HomeTabNavigatorParams,
|
||||
NativeStackScreenProps,
|
||||
} from '#/lib/routes/types'
|
||||
import {logEvent, LogEvents} from '#/lib/statsig/statsig'
|
||||
import {emitSoftReset} from '#/state/events'
|
||||
import {SavedFeedSourceInfo, usePinnedFeedsInfos} from '#/state/queries/feed'
|
||||
@@ -14,16 +26,13 @@ import {UsePreferencesQueryResponse} from '#/state/queries/preferences/types'
|
||||
import {useSession} from '#/state/session'
|
||||
import {useSetDrawerSwipeDisabled, useSetMinimalShellMode} from '#/state/shell'
|
||||
import {useSelectedFeed, useSetSelectedFeed} from '#/state/shell/selected-feed'
|
||||
import {useOTAUpdates} from 'lib/hooks/useOTAUpdates'
|
||||
import {useRequestNotificationsPermission} from 'lib/notifications/notifications'
|
||||
import {HomeTabNavigatorParams, NativeStackScreenProps} from 'lib/routes/types'
|
||||
import {FeedPage} from 'view/com/feeds/FeedPage'
|
||||
import {Pager, PagerRef, RenderTabBarFnProps} from 'view/com/pager/Pager'
|
||||
import {CustomFeedEmptyState} from 'view/com/posts/CustomFeedEmptyState'
|
||||
import {FollowingEmptyState} from 'view/com/posts/FollowingEmptyState'
|
||||
import {FollowingEndOfFeed} from 'view/com/posts/FollowingEndOfFeed'
|
||||
import {FeedPage} from '#/view/com/feeds/FeedPage'
|
||||
import {HomeHeader} from '#/view/com/home/HomeHeader'
|
||||
import {Pager, PagerRef, RenderTabBarFnProps} from '#/view/com/pager/Pager'
|
||||
import {CustomFeedEmptyState} from '#/view/com/posts/CustomFeedEmptyState'
|
||||
import {FollowingEmptyState} from '#/view/com/posts/FollowingEmptyState'
|
||||
import {FollowingEndOfFeed} from '#/view/com/posts/FollowingEndOfFeed'
|
||||
import {NoFeedsPinned} from '#/screens/Home/NoFeedsPinned'
|
||||
import {HomeHeader} from '../com/home/HomeHeader'
|
||||
|
||||
type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home' | 'Start'>
|
||||
export function HomeScreen(props: Props) {
|
||||
@@ -81,6 +90,7 @@ function HomeScreenReady({
|
||||
const selectedIndex = Math.max(0, maybeFoundIndex)
|
||||
const selectedFeed = allFeeds[selectedIndex]
|
||||
const requestNotificationsPermission = useRequestNotificationsPermission()
|
||||
const scrollY = useSharedValue(0)
|
||||
|
||||
useSetTitle(pinnedFeedInfos[selectedIndex]?.displayName)
|
||||
useOTAUpdates()
|
||||
@@ -176,10 +186,11 @@ function HomeScreenReady({
|
||||
testID="homeScreenFeedTabs"
|
||||
onPressSelected={onPressSelected}
|
||||
feeds={pinnedFeedInfos}
|
||||
scrollY={scrollY}
|
||||
/>
|
||||
)
|
||||
},
|
||||
[onPressSelected, pinnedFeedInfos],
|
||||
[onPressSelected, pinnedFeedInfos, scrollY],
|
||||
)
|
||||
|
||||
const renderFollowingEmptyState = React.useCallback(() => {
|
||||
@@ -201,6 +212,15 @@ function HomeScreenReady({
|
||||
}
|
||||
}, [preferences])
|
||||
|
||||
const onScrollWorklet = React.useCallback(
|
||||
(e: NativeScrollEvent) => {
|
||||
'worklet'
|
||||
const nextScrollY = e.contentOffset.y
|
||||
scrollY.value = nextScrollY
|
||||
},
|
||||
[scrollY],
|
||||
)
|
||||
|
||||
return hasSession ? (
|
||||
<Pager
|
||||
key={allFeeds.join(',')}
|
||||
@@ -224,6 +244,7 @@ function HomeScreenReady({
|
||||
feedParams={homeFeedParams}
|
||||
renderEmptyState={renderFollowingEmptyState}
|
||||
renderEndOfFeed={FollowingEndOfFeed}
|
||||
onScroll={onScrollWorklet}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -236,6 +257,7 @@ function HomeScreenReady({
|
||||
feed={feed}
|
||||
renderEmptyState={renderCustomFeedEmptyState}
|
||||
savedFeedConfig={savedFeedConfig}
|
||||
onScroll={onScrollWorklet}
|
||||
/>
|
||||
)
|
||||
})
|
||||
@@ -254,6 +276,7 @@ function HomeScreenReady({
|
||||
isPageFocused
|
||||
feed={`feedgen|${PROD_DEFAULT_FEED('whats-hot')}`}
|
||||
renderEmptyState={renderCustomFeedEmptyState}
|
||||
onScroll={onScrollWorklet}
|
||||
/>
|
||||
</Pager>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user