Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

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

Collection of moderation fixes (#4566)

* Fix: dont blur parents in threads that embed blocks

* After tapping 'Show hidden replies', show the individual hider cards

* Add shape override to UserAvatar and fix the fallback avi for labelers

* Fix precedence

* Detect shape for DefaultAvatar

---------

Co-authored-by: Dan Abramov <dan.abramov@gmail.com>

authored by

Paul Frazee
Dan Abramov
and committed by
GitHub
07c2be25 ac08c761

+41 -14
+2
src/components/moderation/PostAlerts.tsx
··· 92 92 <UserAvatar 93 93 avatar={desc.sourceAvi} 94 94 size={size === 'large' ? 16 : 12} 95 + type="labeler" 96 + shape="circle" 95 97 /> 96 98 ) : ( 97 99 <desc.icon size="sm" fill={t.atoms.text_contrast_medium.color} />
+10 -2
src/components/moderation/PostHider.tsx
··· 1 1 import React, {ComponentProps} from 'react' 2 2 import {Pressable, StyleProp, StyleSheet, View, ViewStyle} from 'react-native' 3 - import {AppBskyActorDefs, ModerationUI} from '@atproto/api' 3 + import {AppBskyActorDefs, ModerationCause, ModerationUI} from '@atproto/api' 4 4 import {msg, Trans} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 6 import {useQueryClient} from '@tanstack/react-query' ··· 45 45 const [override, setOverride] = React.useState(false) 46 46 const control = useModerationDetailsDialogControl() 47 47 const blur = 48 - modui.blurs[0] || (interpretFilterAsBlur ? modui.filters[0] : undefined) 48 + modui.blurs[0] || 49 + (interpretFilterAsBlur ? getBlurrableFilter(modui) : undefined) 49 50 const desc = useModerationCauseDescription(blur) 50 51 51 52 const onBeforePress = React.useCallback(() => { ··· 132 133 {children} 133 134 </Link> 134 135 ) 136 + } 137 + 138 + function getBlurrableFilter(modui: ModerationUI): ModerationCause | undefined { 139 + // moderation causes get "downgraded" when they originate from embedded content 140 + // a downgraded cause should *only* drive filtering in feeds, so we want to look 141 + // for filters that arent downgraded 142 + return modui.filters.find(filter => !filter.downgraded) 135 143 } 136 144 137 145 const styles = StyleSheet.create({
+5 -1
src/view/com/post-thread/PostThread.tsx
··· 331 331 <PostThreadShowHiddenReplies 332 332 type={item === SHOW_HIDDEN_REPLIES ? 'hidden' : 'muted'} 333 333 onPress={() => 334 - setHiddenRepliesState(HiddenRepliesState.ShowAndOverridePostHider) 334 + setHiddenRepliesState( 335 + item === SHOW_HIDDEN_REPLIES 336 + ? HiddenRepliesState.Show 337 + : HiddenRepliesState.ShowAndOverridePostHider, 338 + ) 335 339 } 336 340 hideTopBorder={index === 0} 337 341 />
+24 -11
src/view/com/util/UserAvatar.tsx
··· 35 35 36 36 interface BaseUserAvatarProps { 37 37 type?: UserAvatarType 38 + shape?: 'circle' | 'square' 38 39 size: number 39 40 avatar?: string | null 40 41 } ··· 60 61 61 62 let DefaultAvatar = ({ 62 63 type, 64 + shape: overrideShape, 63 65 size, 64 66 }: { 65 67 type: UserAvatarType 68 + shape?: 'square' | 'circle' 66 69 size: number 67 70 }): React.ReactNode => { 71 + const finalShape = overrideShape ?? (type === 'user' ? 'circle' : 'square') 68 72 if (type === 'algo') { 73 + // TODO: shape=circle 69 74 // Font Awesome Pro 6.4.0 by @fontawesome -https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. 70 75 return ( 71 76 <Svg ··· 84 89 ) 85 90 } 86 91 if (type === 'list') { 92 + // TODO: shape=circle 87 93 // Font Awesome Pro 6.4.0 by @fontawesome -https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. 88 94 return ( 89 95 <Svg ··· 117 123 viewBox="0 0 32 32" 118 124 fill="none" 119 125 stroke="none"> 120 - <Rect 121 - x="0" 122 - y="0" 123 - width="32" 124 - height="32" 125 - rx="3" 126 - fill={tokens.color.temp_purple} 127 - /> 126 + {finalShape === 'square' ? ( 127 + <Rect 128 + x="0" 129 + y="0" 130 + width="32" 131 + height="32" 132 + rx="3" 133 + fill={tokens.color.temp_purple} 134 + /> 135 + ) : ( 136 + <Circle cx="16" cy="16" r="16" fill={tokens.color.temp_purple} /> 137 + )} 128 138 <Path 129 139 d="M24 9.75L16 7L8 9.75V15.9123C8 20.8848 12 23 16 25.1579C20 23 24 20.8848 24 15.9123V9.75Z" 130 140 stroke="white" ··· 135 145 </Svg> 136 146 ) 137 147 } 148 + // TODO: shape=square 138 149 return ( 139 150 <Svg 140 151 testID="userAvatarFallback" ··· 159 170 160 171 let UserAvatar = ({ 161 172 type = 'user', 173 + shape: overrideShape, 162 174 size, 163 175 avatar, 164 176 moderation, ··· 166 178 }: UserAvatarProps): React.ReactNode => { 167 179 const pal = usePalette('default') 168 180 const backgroundColor = pal.colors.backgroundLight 181 + const finalShape = overrideShape ?? (type === 'user' ? 'circle' : 'square') 169 182 170 183 const aviStyle = useMemo(() => { 171 - if (type === 'algo' || type === 'list' || type === 'labeler') { 184 + if (finalShape === 'square') { 172 185 return { 173 186 width: size, 174 187 height: size, ··· 182 195 borderRadius: Math.floor(size / 2), 183 196 backgroundColor, 184 197 } 185 - }, [type, size, backgroundColor]) 198 + }, [finalShape, size, backgroundColor]) 186 199 187 200 const alert = useMemo(() => { 188 201 if (!moderation?.alert) { ··· 224 237 </View> 225 238 ) : ( 226 239 <View style={{width: size, height: size}}> 227 - <DefaultAvatar type={type} size={size} /> 240 + <DefaultAvatar type={type} shape={finalShape} size={size} /> 228 241 {alert} 229 242 </View> 230 243 )