Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

redo expanding banner code, fix HQ images for pfp n banner

+89 -73
+79 -11
src/screens/Profile/Header/Shell.tsx
··· 22 22 import {isIOS} from '#/platform/detection' 23 23 import {type Shadow} from '#/state/cache/types' 24 24 import {useLightboxControls} from '#/state/lightbox' 25 + import { 26 + maybeModifyHighQualityImage, 27 + useHighQualityImages, 28 + } from '#/state/preferences/high-quality-images' 25 29 import {useSession} from '#/state/session' 26 30 import {LoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' 27 31 import {UserAvatar} from '#/view/com/util/UserAvatar' ··· 61 65 const {top: topInset} = useSafeAreaInsets() 62 66 const playHaptic = useHaptics() 63 67 const liveStatusControl = useDialogControl() 68 + const highQualityImages = useHighQualityImages() 64 69 65 70 const aviRef = useAnimatedRef() 71 + const bannerRef = useAnimatedRef() 66 72 67 73 const onPressBack = useCallback(() => { 68 74 if (navigation.canGoBack()) { ··· 72 78 } 73 79 }, [navigation]) 74 80 75 - const _openLightbox = useCallback( 81 + const _openLightboxAvi = useCallback( 76 82 (uri: string, thumbRect: MeasuredDimensions | null) => { 77 83 openLightbox({ 78 84 images: [ 79 85 { 80 - uri, 81 - thumbUri: uri, 86 + uri: maybeModifyHighQualityImage(uri, highQualityImages), 87 + thumbUri: maybeModifyHighQualityImage(uri, highQualityImages), 82 88 thumbRect, 83 89 dimensions: { 84 90 // It's fine if it's actually smaller but we know it's 1:1. ··· 92 98 index: 0, 93 99 }) 94 100 }, 95 - [openLightbox], 101 + [openLightbox, highQualityImages], 102 + ) 103 + 104 + // theres probs a better way instead of just making a separate one but this works:tm: so its whatever 105 + const _openLightboxBanner = useCallback( 106 + (uri: string, thumbRect: MeasuredDimensions | null) => { 107 + openLightbox({ 108 + images: [ 109 + { 110 + uri: maybeModifyHighQualityImage(uri, highQualityImages), 111 + thumbUri: maybeModifyHighQualityImage(uri, highQualityImages), 112 + thumbRect, 113 + dimensions: thumbRect, 114 + thumbDimensions: null, 115 + type: 'image', 116 + }, 117 + ], 118 + index: 0, 119 + }) 120 + }, 121 + [openLightbox, highQualityImages], 96 122 ) 97 123 98 124 const isMe = useMemo( ··· 128 154 runOnUI(() => { 129 155 'worklet' 130 156 const rect = measure(aviRef) 131 - runOnJS(_openLightbox)(avatar, rect) 157 + runOnJS(_openLightboxAvi)(avatar, rect) 132 158 })() 133 159 } 134 160 } 135 161 }, [ 136 162 profile, 137 163 moderation, 138 - _openLightbox, 164 + _openLightboxAvi, 139 165 aviRef, 140 166 liveStatusControl, 141 167 live, 142 168 playHaptic, 143 169 ]) 144 170 171 + const onPressBanner = useCallback(() => { 172 + if (live.isActive) { 173 + playHaptic('Light') 174 + logger.metric( 175 + 'live:card:open', 176 + {subject: profile.did, from: 'profile'}, 177 + {statsig: true}, 178 + ) 179 + liveStatusControl.open() 180 + } else { 181 + const modui = moderation.ui('banner') 182 + const banner = profile.banner 183 + if (banner && !(modui.blur && modui.noOverride)) { 184 + runOnUI(() => { 185 + 'worklet' 186 + const rect = measure(bannerRef) 187 + runOnJS(_openLightboxBanner)(banner, rect) 188 + })() 189 + } 190 + } 191 + }, [ 192 + profile, 193 + moderation, 194 + _openLightboxBanner, 195 + bannerRef, 196 + liveStatusControl, 197 + live, 198 + playHaptic, 199 + ]) 200 + 145 201 return ( 146 202 <View style={t.atoms.bg} pointerEvents={isIOS ? 'auto' : 'box-none'}> 147 203 <View ··· 198 254 style={{borderRadius: 0}} 199 255 /> 200 256 ) : ( 201 - <UserBanner 202 - type={profile.associated?.labeler ? 'labeler' : 'default'} 203 - banner={profile.banner} 204 - moderation={moderation.ui('banner')} 205 - /> 257 + <TouchableWithoutFeedback 258 + testID="profileHeaderBannerButton" 259 + onPress={onPressBanner} 260 + accessibilityRole="image" 261 + accessibilityLabel={_(msg`View ${profile.handle}'s banner`)} 262 + accessibilityHint=""> 263 + <View> 264 + <Animated.View ref={bannerRef} collapsable={false}> 265 + <UserBanner 266 + type={profile.associated?.labeler ? 'labeler' : 'default'} 267 + banner={profile.banner} 268 + moderation={moderation.ui('banner')} 269 + /> 270 + {live.isActive && <LiveIndicator size="large" />} 271 + </Animated.View> 272 + </View> 273 + </TouchableWithoutFeedback> 206 274 )} 207 275 </GrowableBanner> 208 276 </View>
+10 -62
src/view/com/util/UserBanner.tsx
··· 1 1 import {useCallback, useState} from 'react' 2 - import { 3 - Pressable, 4 - StyleSheet, 5 - TouchableWithoutFeedback, 6 - View, 7 - } from 'react-native' 8 - import { 9 - measure, 10 - type MeasuredDimensions, 11 - runOnJS, 12 - runOnUI, 13 - useAnimatedRef, 14 - } from 'react-native-reanimated' 2 + import {Pressable, StyleSheet, View} from 'react-native' 15 3 import {Image} from 'expo-image' 16 4 import {type ModerationUI} from '@atproto/api' 17 5 import {msg, Trans} from '@lingui/macro' ··· 31 19 compressImage, 32 20 createComposerImage, 33 21 } from '#/state/gallery' 34 - import {useLightboxControls} from '#/state/lightbox' 35 22 import { 36 23 maybeModifyHighQualityImage, 37 24 useHighQualityImages, ··· 67 54 const sheetWrapper = useSheetWrapper() 68 55 const [rawImage, setRawImage] = useState<ComposerImage | undefined>() 69 56 const editImageDialogControl = useDialogControl() 70 - const {openLightbox} = useLightboxControls() 71 57 const highQualityImages = useHighQualityImages() 72 - 73 - const bannerRef = useAnimatedRef() 74 58 75 59 const onOpenCamera = useCallback(async () => { 76 60 if (!(await requestCameraAccessIfNeeded())) { ··· 124 108 onSelectNewBanner?.(null) 125 109 }, [onSelectNewBanner]) 126 110 127 - const _openLightbox = useCallback( 128 - (uri: string, thumbRect: MeasuredDimensions | null) => { 129 - openLightbox({ 130 - images: [ 131 - { 132 - uri: maybeModifyHighQualityImage(uri, highQualityImages), 133 - thumbUri: maybeModifyHighQualityImage(uri, highQualityImages), 134 - thumbRect, 135 - dimensions: thumbRect, 136 - thumbDimensions: null, 137 - type: 'image', 138 - }, 139 - ], 140 - index: 0, 141 - }) 142 - }, 143 - [openLightbox, highQualityImages], 144 - ) 145 - 146 - const onPressBanner = useCallback(() => { 147 - if (banner && !(moderation?.blur && moderation?.noOverride)) { 148 - runOnUI(() => { 149 - 'worklet' 150 - const rect = measure(bannerRef) 151 - runOnJS(_openLightbox)(banner, rect) 152 - })() 153 - } 154 - }, [banner, moderation, _openLightbox, bannerRef]) 155 - 156 111 const onChangeEditImage = useCallback( 157 112 async (image: ComposerImage) => { 158 113 const compressed = await compressImage(image) ··· 261 216 </> 262 217 ) : banner && 263 218 !((moderation?.blur && isAndroid) /* android crashes with blur */) ? ( 264 - <TouchableWithoutFeedback 265 - testID="profileHeaderAviButton" 266 - onPress={onPressBanner} 267 - accessibilityRole="image" 268 - accessibilityLabel={_(msg`View profile banner`)} 269 - accessibilityHint=""> 270 - <Image 271 - testID="userBannerImage" 272 - style={[styles.bannerImage, t.atoms.bg_contrast_25]} 273 - contentFit="cover" 274 - source={{uri: maybeModifyHighQualityImage(banner, highQualityImages)}} 275 - blurRadius={moderation?.blur ? 100 : 0} 276 - accessible={true} 277 - accessibilityIgnoresInvertColors 278 - /> 279 - </TouchableWithoutFeedback> 219 + <Image 220 + testID="userBannerImage" 221 + style={[styles.bannerImage, t.atoms.bg_contrast_25]} 222 + contentFit="cover" 223 + source={{uri: maybeModifyHighQualityImage(banner, highQualityImages)}} 224 + blurRadius={moderation?.blur ? 100 : 0} 225 + accessible={true} 226 + accessibilityIgnoresInvertColors 227 + /> 280 228 ) : ( 281 229 <View 282 230 testID="userBannerFallback"