wip fancy banner
This commit is contained in:
@@ -2,6 +2,7 @@ import React, {useEffect, useState} from 'react'
|
|||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {ActivityIndicator} from 'react-native'
|
import {ActivityIndicator} from 'react-native'
|
||||||
import Animated, {
|
import Animated, {
|
||||||
|
clamp,
|
||||||
Extrapolation,
|
Extrapolation,
|
||||||
interpolate,
|
interpolate,
|
||||||
runOnJS,
|
runOnJS,
|
||||||
@@ -14,7 +15,7 @@ import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
|||||||
import {BlurView} from 'expo-blur'
|
import {BlurView} from 'expo-blur'
|
||||||
import {useIsFetching} from '@tanstack/react-query'
|
import {useIsFetching} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {isIOS} from '#/platform/detection'
|
import {isIOS, isWeb} from '#/platform/detection'
|
||||||
import {RQKEY_ROOT as STARTERPACK_RQKEY_ROOT} from '#/state/queries/actor-starter-packs'
|
import {RQKEY_ROOT as STARTERPACK_RQKEY_ROOT} from '#/state/queries/actor-starter-packs'
|
||||||
import {RQKEY_ROOT as FEED_RQKEY_ROOT} from '#/state/queries/post-feed'
|
import {RQKEY_ROOT as FEED_RQKEY_ROOT} from '#/state/queries/post-feed'
|
||||||
import {RQKEY_ROOT as FEEDGEN_RQKEY_ROOT} from '#/state/queries/profile-feedgens'
|
import {RQKEY_ROOT as FEEDGEN_RQKEY_ROOT} from '#/state/queries/profile-feedgens'
|
||||||
@@ -33,8 +34,8 @@ export function GrowableBanner({
|
|||||||
}) {
|
}) {
|
||||||
const pagerContext = usePagerHeaderContext()
|
const pagerContext = usePagerHeaderContext()
|
||||||
|
|
||||||
// plain non-growable mode for Android/Web
|
// plain non-growable mode for Web
|
||||||
if (!pagerContext || !isIOS) {
|
if (!pagerContext || isWeb) {
|
||||||
return (
|
return (
|
||||||
<View style={[a.w_full, a.h_full]}>
|
<View style={[a.w_full, a.h_full]}>
|
||||||
{children}
|
{children}
|
||||||
@@ -43,20 +44,28 @@ export function GrowableBanner({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const {scrollY} = pagerContext
|
const {scrollY, headerHeight, minimumHeaderHeight} = pagerContext
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GrowableBannerInner scrollY={scrollY} backButton={backButton}>
|
<GrowableBannerInner
|
||||||
|
scrollY={scrollY}
|
||||||
|
backButton={backButton}
|
||||||
|
headerHeight={headerHeight}
|
||||||
|
minimumHeaderHeight={minimumHeaderHeight}>
|
||||||
{children}
|
{children}
|
||||||
</GrowableBannerInner>
|
</GrowableBannerInner>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function GrowableBannerInner({
|
function GrowableBannerInner({
|
||||||
|
headerHeight,
|
||||||
|
minimumHeaderHeight,
|
||||||
scrollY,
|
scrollY,
|
||||||
backButton,
|
backButton,
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
|
headerHeight: number
|
||||||
|
minimumHeaderHeight: number
|
||||||
scrollY: SharedValue<number>
|
scrollY: SharedValue<number>
|
||||||
backButton?: React.ReactNode
|
backButton?: React.ReactNode
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
@@ -68,20 +77,33 @@ function GrowableBannerInner({
|
|||||||
const animatedStyle = useAnimatedStyle(() => ({
|
const animatedStyle = useAnimatedStyle(() => ({
|
||||||
transform: [
|
transform: [
|
||||||
{
|
{
|
||||||
scale: interpolate(scrollY.get(), [-150, 0], [2, 1], {
|
scale: interpolate(
|
||||||
extrapolateRight: Extrapolation.CLAMP,
|
scrollY.get(),
|
||||||
}),
|
[-150, 0],
|
||||||
|
[2, 1],
|
||||||
|
Extrapolation.CLAMP,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
translateY: clamp(scrollY.get() - minimumHeaderHeight, 0, headerHeight),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const animatedBlurViewProps = useAnimatedProps(() => {
|
const animatedBlurViewProps = useAnimatedProps(() => {
|
||||||
|
console.log(
|
||||||
|
'scrollY',
|
||||||
|
scrollY.get(),
|
||||||
|
'headerHeight',
|
||||||
|
headerHeight,
|
||||||
|
topInset,
|
||||||
|
)
|
||||||
return {
|
return {
|
||||||
intensity: interpolate(
|
intensity: interpolate(
|
||||||
scrollY.get(),
|
scrollY.get(),
|
||||||
[-300, -65, -15],
|
[-300, -65, -15, minimumHeaderHeight - 10, minimumHeaderHeight],
|
||||||
[50, 40, 0],
|
[50, 40, 0, 0, 50],
|
||||||
Extrapolation.CLAMP,
|
{extrapolateLeft: Extrapolation.CLAMP},
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -97,7 +97,6 @@ const MinimalHeader = React.memo(function MinimalHeader({
|
|||||||
profile: AppBskyActorDefs.ProfileViewDetailed
|
profile: AppBskyActorDefs.ProfileViewDetailed
|
||||||
hideBackButton?: boolean
|
hideBackButton?: boolean
|
||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
|
||||||
const insets = useSafeAreaInsets()
|
const insets = useSafeAreaInsets()
|
||||||
const ctx = usePagerHeaderContext()
|
const ctx = usePagerHeaderContext()
|
||||||
const [visible, setVisible] = useState(false)
|
const [visible, setVisible] = useState(false)
|
||||||
@@ -153,7 +152,6 @@ const MinimalHeader = React.memo(function MinimalHeader({
|
|||||||
style={[
|
style={[
|
||||||
a.absolute,
|
a.absolute,
|
||||||
a.z_50,
|
a.z_50,
|
||||||
t.atoms.bg,
|
|
||||||
{
|
{
|
||||||
top: 0,
|
top: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {isNative} from '#/platform/detection'
|
|||||||
export const PagerHeaderContext = React.createContext<{
|
export const PagerHeaderContext = React.createContext<{
|
||||||
scrollY: SharedValue<number>
|
scrollY: SharedValue<number>
|
||||||
headerHeight: number
|
headerHeight: number
|
||||||
|
minimumHeaderHeight: number
|
||||||
} | null>(null)
|
} | null>(null)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -17,15 +18,17 @@ export const PagerHeaderContext = React.createContext<{
|
|||||||
export function PagerHeaderProvider({
|
export function PagerHeaderProvider({
|
||||||
scrollY,
|
scrollY,
|
||||||
headerHeight,
|
headerHeight,
|
||||||
|
minimumHeaderHeight,
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
scrollY: SharedValue<number>
|
scrollY: SharedValue<number>
|
||||||
headerHeight: number
|
headerHeight: number
|
||||||
|
minimumHeaderHeight: number
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
}) {
|
}) {
|
||||||
const value = React.useMemo(
|
const value = React.useMemo(
|
||||||
() => ({scrollY, headerHeight}),
|
() => ({scrollY, headerHeight, minimumHeaderHeight}),
|
||||||
[scrollY, headerHeight],
|
[scrollY, headerHeight, minimumHeaderHeight],
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
<PagerHeaderContext.Provider value={value}>
|
<PagerHeaderContext.Provider value={value}>
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>(
|
|||||||
const [currentPage, setCurrentPage] = React.useState(0)
|
const [currentPage, setCurrentPage] = React.useState(0)
|
||||||
const [tabBarHeight, setTabBarHeight] = React.useState(0)
|
const [tabBarHeight, setTabBarHeight] = React.useState(0)
|
||||||
const [headerOnlyHeight, setHeaderOnlyHeight] = React.useState(0)
|
const [headerOnlyHeight, setHeaderOnlyHeight] = React.useState(0)
|
||||||
|
const [minimumHeaderHeight, setMinimumHeaderHeight] = React.useState(0)
|
||||||
const scrollY = useSharedValue(0)
|
const scrollY = useSharedValue(0)
|
||||||
const headerHeight = headerOnlyHeight + tabBarHeight
|
const headerHeight = headerOnlyHeight + tabBarHeight
|
||||||
|
|
||||||
@@ -89,7 +90,8 @@ export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>(
|
|||||||
return (
|
return (
|
||||||
<PagerHeaderProvider
|
<PagerHeaderProvider
|
||||||
scrollY={scrollY}
|
scrollY={scrollY}
|
||||||
headerHeight={headerOnlyHeight}>
|
headerHeight={headerOnlyHeight}
|
||||||
|
minimumHeaderHeight={minimumHeaderHeight}>
|
||||||
<PagerTabBar
|
<PagerTabBar
|
||||||
headerOnlyHeight={headerOnlyHeight}
|
headerOnlyHeight={headerOnlyHeight}
|
||||||
items={items}
|
items={items}
|
||||||
@@ -105,6 +107,8 @@ export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>(
|
|||||||
allowHeaderOverScroll={allowHeaderOverScroll}
|
allowHeaderOverScroll={allowHeaderOverScroll}
|
||||||
dragProgress={props.dragProgress}
|
dragProgress={props.dragProgress}
|
||||||
dragState={props.dragState}
|
dragState={props.dragState}
|
||||||
|
minimumHeaderHeight={minimumHeaderHeight}
|
||||||
|
setMinimumHeaderHeight={setMinimumHeaderHeight}
|
||||||
/>
|
/>
|
||||||
</PagerHeaderProvider>
|
</PagerHeaderProvider>
|
||||||
)
|
)
|
||||||
@@ -121,6 +125,8 @@ export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>(
|
|||||||
scrollY,
|
scrollY,
|
||||||
testID,
|
testID,
|
||||||
allowHeaderOverScroll,
|
allowHeaderOverScroll,
|
||||||
|
minimumHeaderHeight,
|
||||||
|
setMinimumHeaderHeight,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -236,6 +242,8 @@ let PagerTabBar = ({
|
|||||||
allowHeaderOverScroll,
|
allowHeaderOverScroll,
|
||||||
dragProgress,
|
dragProgress,
|
||||||
dragState,
|
dragState,
|
||||||
|
minimumHeaderHeight,
|
||||||
|
setMinimumHeaderHeight,
|
||||||
}: {
|
}: {
|
||||||
currentPage: number
|
currentPage: number
|
||||||
headerOnlyHeight: number
|
headerOnlyHeight: number
|
||||||
@@ -255,8 +263,9 @@ let PagerTabBar = ({
|
|||||||
allowHeaderOverScroll?: boolean
|
allowHeaderOverScroll?: boolean
|
||||||
dragProgress: SharedValue<number>
|
dragProgress: SharedValue<number>
|
||||||
dragState: SharedValue<'idle' | 'dragging' | 'settling'>
|
dragState: SharedValue<'idle' | 'dragging' | 'settling'>
|
||||||
|
minimumHeaderHeight: number
|
||||||
|
setMinimumHeaderHeight: (height: number) => void
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
const [minimumHeaderHeight, setMinimumHeaderHeight] = React.useState(0)
|
|
||||||
const headerTransform = useAnimatedStyle(() => {
|
const headerTransform = useAnimatedStyle(() => {
|
||||||
const translateY =
|
const translateY =
|
||||||
Math.min(
|
Math.min(
|
||||||
|
|||||||
Reference in New Issue
Block a user