Bluesky app fork with some witchin' additions 💫

Remove LiveIndicator from banner & make avatar lightbox accessible for live accounts

Open profile is replaced with View avatar when you're on a profile of a live user. (Could probably remove the rest of the lightbox TouchableWithoutFeedback element here in favor of Bluesky's official implementation upstream and just above on line :205?)

xan.lol 50bb9174 6982eb4f

verified
+50 -12
+38 -9
src/components/live/LiveStatusDialog.tsx
··· 32 profile, 33 embed, 34 status, 35 }: { 36 control: Dialog.DialogControlProps 37 profile: bsky.profile.AnyProfileView 38 status: AppBskyActorDefs.StatusView 39 embed: AppBskyEmbedExternal.View 40 }) { 41 const navigation = useNavigation<NavigationProp>() 42 return ( ··· 47 profile={profile} 48 embed={embed} 49 navigation={navigation} 50 /> 51 </Dialog.Outer> 52 ) ··· 57 embed, 58 navigation, 59 status, 60 }: { 61 profile: bsky.profile.AnyProfileView 62 embed: AppBskyEmbedExternal.View 63 navigation: NavigationProp 64 status: AppBskyActorDefs.StatusView 65 }) { 66 const {_} = useLingui() 67 const control = Dialog.useDialogContext() ··· 74 }) 75 }, [navigation, profile.handle, control]) 76 77 return ( 78 <Dialog.ScrollableInner 79 label={_(msg`${sanitizeHandle(profile.handle)} is live`)} ··· 84 profile={profile} 85 embed={embed} 86 onPressOpenProfile={onPressOpenProfile} 87 /> 88 <Dialog.Close /> 89 </Dialog.ScrollableInner> ··· 96 embed, 97 padding = 'xl', 98 onPressOpenProfile, 99 }: { 100 status: AppBskyActorDefs.StatusView 101 profile: bsky.profile.AnyProfileView 102 embed: AppBskyEmbedExternal.View 103 padding?: 'lg' | 'xl' 104 onPressOpenProfile: () => void 105 }) { 106 const {_} = useLingui() 107 const t = useTheme() ··· 202 /> 203 </View> 204 <Button 205 - label={_(msg`Open profile`)} 206 size="small" 207 color="secondary" 208 variant="solid" 209 onPress={() => { 210 - logger.metric( 211 - 'live:card:openProfile', 212 - {subject: profile.did}, 213 - {statsig: true}, 214 - ) 215 - unstableCacheProfileView(queryClient, profile) 216 - onPressOpenProfile() 217 }}> 218 <ButtonText> 219 - <Trans>Open profile</Trans> 220 </ButtonText> 221 </Button> 222 </ProfileCard.Header>
··· 32 profile, 33 embed, 34 status, 35 + onPressViewAvatar, 36 }: { 37 control: Dialog.DialogControlProps 38 profile: bsky.profile.AnyProfileView 39 status: AppBskyActorDefs.StatusView 40 embed: AppBskyEmbedExternal.View 41 + onPressViewAvatar?: () => void 42 }) { 43 const navigation = useNavigation<NavigationProp>() 44 return ( ··· 49 profile={profile} 50 embed={embed} 51 navigation={navigation} 52 + onPressViewAvatar={onPressViewAvatar} 53 /> 54 </Dialog.Outer> 55 ) ··· 60 embed, 61 navigation, 62 status, 63 + onPressViewAvatar, 64 }: { 65 profile: bsky.profile.AnyProfileView 66 embed: AppBskyEmbedExternal.View 67 navigation: NavigationProp 68 status: AppBskyActorDefs.StatusView 69 + onPressViewAvatar?: () => void 70 }) { 71 const {_} = useLingui() 72 const control = Dialog.useDialogContext() ··· 79 }) 80 }, [navigation, profile.handle, control]) 81 82 + const handlePressViewAvatar = useCallback(() => { 83 + if (onPressViewAvatar) { 84 + control.close(onPressViewAvatar) 85 + } 86 + }, [control, onPressViewAvatar]) 87 + 88 return ( 89 <Dialog.ScrollableInner 90 label={_(msg`${sanitizeHandle(profile.handle)} is live`)} ··· 95 profile={profile} 96 embed={embed} 97 onPressOpenProfile={onPressOpenProfile} 98 + onPressViewAvatar={handlePressViewAvatar} 99 /> 100 <Dialog.Close /> 101 </Dialog.ScrollableInner> ··· 108 embed, 109 padding = 'xl', 110 onPressOpenProfile, 111 + onPressViewAvatar, 112 }: { 113 status: AppBskyActorDefs.StatusView 114 profile: bsky.profile.AnyProfileView 115 embed: AppBskyEmbedExternal.View 116 padding?: 'lg' | 'xl' 117 onPressOpenProfile: () => void 118 + onPressViewAvatar?: () => void 119 }) { 120 const {_} = useLingui() 121 const t = useTheme() ··· 216 /> 217 </View> 218 <Button 219 + label={ 220 + onPressViewAvatar ? _(msg`View avatar`) : _(msg`Open profile`) 221 + } 222 size="small" 223 color="secondary" 224 variant="solid" 225 onPress={() => { 226 + if (onPressViewAvatar) { 227 + logger.metric( 228 + 'live:card:viewAvatar', 229 + {subject: profile.did}, 230 + {statsig: true}, 231 + ) 232 + onPressViewAvatar() 233 + } else { 234 + logger.metric( 235 + 'live:card:openProfile', 236 + {subject: profile.did}, 237 + {statsig: true}, 238 + ) 239 + unstableCacheProfileView(queryClient, profile) 240 + onPressOpenProfile() 241 + } 242 }}> 243 <ButtonText> 244 + {onPressViewAvatar ? ( 245 + <Trans>View avatar</Trans> 246 + ) : ( 247 + <Trans>Open profile</Trans> 248 + )} 249 </ButtonText> 250 </Button> 251 </ProfileCard.Header>
+1 -2
src/logger/metrics.ts
··· 374 | 'AvatarButton' 375 | 'StarterPackProfilesList' 376 | 'FeedInterstitial' 377 - | 'ProfileHeaderSuggestedFollows' 378 | 'PostOnboardingFindFollows' 379 | 'ImmersiveVideo' 380 | 'ExploreSuggestedAccounts' ··· 468 | 'AvatarButton' 469 | 'StarterPackProfilesList' 470 | 'FeedInterstitial' 471 - | 'ProfileHeaderSuggestedFollows' 472 | 'PostOnboardingFindFollows' 473 | 'ImmersiveVideo' 474 | 'ExploreSuggestedAccounts' ··· 632 'live:card:open': {subject: string; from: 'post' | 'profile'} 633 'live:card:watch': {subject: string} 634 'live:card:openProfile': {subject: string} 635 'live:view:profile': {subject: string} 636 'live:view:post': {subject: string; feed?: string} 637
··· 374 | 'AvatarButton' 375 | 'StarterPackProfilesList' 376 | 'FeedInterstitial' 377 | 'PostOnboardingFindFollows' 378 | 'ImmersiveVideo' 379 | 'ExploreSuggestedAccounts' ··· 467 | 'AvatarButton' 468 | 'StarterPackProfilesList' 469 | 'FeedInterstitial' 470 | 'PostOnboardingFindFollows' 471 | 'ImmersiveVideo' 472 | 'ExploreSuggestedAccounts' ··· 630 'live:card:open': {subject: string; from: 'post' | 'profile'} 631 'live:card:watch': {subject: string} 632 'live:card:openProfile': {subject: string} 633 + 'live:card:viewAvatar': {subject: string} 634 'live:view:profile': {subject: string} 635 'live:view:post': {subject: string; feed?: string} 636
+11 -1
src/screens/Profile/Header/Shell.tsx
··· 266 banner={profile.banner} 267 moderation={moderation.ui('banner')} 268 /> 269 - {live.isActive && <LiveIndicator size="large" />} 270 </Animated.View> 271 </View> 272 </TouchableWithoutFeedback> ··· 348 status={live} 349 embed={live.embed} 350 profile={profile} 351 /> 352 ))} 353 </View>
··· 266 banner={profile.banner} 267 moderation={moderation.ui('banner')} 268 /> 269 </Animated.View> 270 </View> 271 </TouchableWithoutFeedback> ··· 347 status={live} 348 embed={live.embed} 349 profile={profile} 350 + onPressViewAvatar={() => { 351 + const modui = moderation.ui('avatar') 352 + const avatar = profile.avatar 353 + if (avatar && !(modui.blur && modui.noOverride)) { 354 + runOnUI(() => { 355 + 'worklet' 356 + const rect = measure(aviRef) 357 + runOnJS(_openLightbox)(avatar, rect) 358 + })() 359 + } 360 + }} 361 /> 362 ))} 363 </View>