From 0deb9511af0e193f77181cc55e90c75b82074165 Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Tue, 6 Jan 2026 20:37:47 +0200 Subject: [PATCH] Enable lightbox for profile banner (#9643) * allow pressing banner to view * remove special type --- src/screens/Profile/Header/GrowableBanner.tsx | 43 ++++++++++++++--- src/screens/Profile/Header/Shell.tsx | 46 +++++++++++++++---- 2 files changed, 72 insertions(+), 17 deletions(-) diff --git a/src/screens/Profile/Header/GrowableBanner.tsx b/src/screens/Profile/Header/GrowableBanner.tsx index ab1432bdca..fced6a5e0c 100644 --- a/src/screens/Profile/Header/GrowableBanner.tsx +++ b/src/screens/Profile/Header/GrowableBanner.tsx @@ -1,7 +1,7 @@ import {useEffect, useState} from 'react' -import {View} from 'react-native' -import {ActivityIndicator} from 'react-native' +import {ActivityIndicator, Pressable, View} from 'react-native' import Animated, { + type AnimatedRef, Extrapolation, interpolate, runOnJS, @@ -28,26 +28,39 @@ const AnimatedBlurView = Animated.createAnimatedComponent(BlurView) export function GrowableBanner({ backButton, children, + onPress, + bannerRef, }: { backButton?: React.ReactNode children: React.ReactNode + onPress?: () => void + bannerRef?: AnimatedRef }) { const pagerContext = usePagerHeaderContext() // plain non-growable mode for Android/Web if (!pagerContext || !isIOS) { return ( - - {children} + + + {children} + {backButton} - + ) } const {scrollY} = pagerContext return ( - + {children} ) @@ -57,10 +70,14 @@ function GrowableBannerInner({ scrollY, backButton, children, + onPress, + bannerRef, }: { scrollY: SharedValue backButton?: React.ReactNode children: React.ReactNode + onPress?: () => void + bannerRef?: AnimatedRef }) { const {top: topInset} = useSafeAreaInsets() const isFetching = useIsProfileFetching() @@ -124,14 +141,26 @@ function GrowableBannerInner({ {transformOrigin: 'bottom'}, animatedStyle, ]}> - {children} + + + {children} + + () const onPressBack = useCallback(() => { if (navigation.canGoBack()) { @@ -73,20 +74,31 @@ let ProfileHeaderShell = ({ }, [navigation]) const _openLightbox = useCallback( - (uri: string, thumbRect: MeasuredDimensions | null) => { + ( + uri: string, + thumbRect: MeasuredDimensions | null, + type: 'circle-avi' | 'image' = 'circle-avi', + ) => { openLightbox({ images: [ { uri, thumbUri: uri, thumbRect, - dimensions: { - // It's fine if it's actually smaller but we know it's 1:1. - height: 1000, - width: 1000, - }, + dimensions: + type === 'circle-avi' + ? { + // It's fine if it's actually smaller but we know it's 1:1. + height: 1000, + width: 1000, + } + : { + // Banner aspect ratio is 3:1 + width: 3000, + height: 1000, + }, thumbDimensions: null, - type: 'circle-avi', + type, }, ], index: 0, @@ -142,6 +154,18 @@ let ProfileHeaderShell = ({ playHaptic, ]) + const onPressBanner = useCallback(() => { + const modui = moderation.ui('banner') + const banner = profile.banner + if (banner && !(modui.blur && modui.noOverride)) { + runOnUI(() => { + 'worklet' + const rect = measure(bannerRef) + runOnJS(_openLightbox)(banner, rect, 'image') + })() + } + }, [profile.banner, moderation, _openLightbox, bannerRef]) + return ( - } - + {live.isActive &&