Use consistent avatar shape/defaults for labelers (#3257)

* Add type: labeler to easy spots

* Search and ProfileCard

* Filter out of suggested follows

* ComposeReplyTo

* PReviewable avatar in posts

* Lists

* PostMeta

* Notifications

* Autocomplete

* Straggler

* Bump sdk
zio/stable
Eric Bailey 2024-03-19 14:18:57 -05:00 committed by GitHub
parent b9474a5d55
commit dfe88e1656
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 87 additions and 58 deletions

View File

@ -46,7 +46,7 @@
"make-deploy-bundle": "bash scripts/bundleUpdate.sh" "make-deploy-bundle": "bash scripts/bundleUpdate.sh"
}, },
"dependencies": { "dependencies": {
"@atproto/api": "^0.12.0", "@atproto/api": "^0.12.1",
"@bam.tech/react-native-image-resizer": "^3.0.4", "@bam.tech/react-native-image-resizer": "^3.0.4",
"@braintree/sanitize-url": "^6.0.2", "@braintree/sanitize-url": "^6.0.2",
"@emoji-mart/react": "^1.1.1", "@emoji-mart/react": "^1.1.1",

View File

@ -101,13 +101,7 @@ function computeSuggestions(
} }
for (const item of searched) { for (const item of searched) {
if (!items.find(item2 => item2.handle === item.handle)) { if (!items.find(item2 => item2.handle === item.handle)) {
items.push({ items.push(item)
did: item.did,
handle: item.handle,
displayName: item.displayName,
avatar: item.avatar,
labels: item.labels,
})
} }
} }
return items.filter(profile => { return items.filter(profile => {

View File

@ -3,6 +3,7 @@ import {
AppBskyEmbedRecord, AppBskyEmbedRecord,
AppBskyRichtextFacet, AppBskyRichtextFacet,
ModerationDecision, ModerationDecision,
AppBskyActorDefs,
} from '@atproto/api' } from '@atproto/api'
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
@ -10,11 +11,7 @@ export interface ComposerOptsPostRef {
uri: string uri: string
cid: string cid: string
text: string text: string
author: { author: AppBskyActorDefs.ProfileViewBasic
handle: string
displayName?: string
avatar?: string
}
embed?: AppBskyEmbedRecord.ViewRecord['embed'] embed?: AppBskyEmbedRecord.ViewRecord['embed']
moderation?: ModerationDecision moderation?: ModerationDecision
} }

View File

@ -45,7 +45,11 @@ function AccountItem({
accessibilityHint={_(msg`Double tap to sign in`)}> accessibilityHint={_(msg`Double tap to sign in`)}>
<View style={[pal.borderDark, styles.groupContent, styles.noTopBorder]}> <View style={[pal.borderDark, styles.groupContent, styles.noTopBorder]}>
<View style={s.p10}> <View style={s.p10}>
<UserAvatar avatar={profile?.avatar} size={30} /> <UserAvatar
avatar={profile?.avatar}
size={30}
type={profile?.associated?.labeler ? 'labeler' : 'user'}
/>
</View> </View>
<Text style={styles.accountText}> <Text style={styles.accountText}>
<Text type="lg-bold" style={pal.text}> <Text type="lg-bold" style={pal.text}>

View File

@ -415,7 +415,11 @@ export const ComposePost = observer(function ComposePost({
styles.textInputLayout, styles.textInputLayout,
isNative && styles.textInputLayoutMobile, isNative && styles.textInputLayoutMobile,
]}> ]}>
<UserAvatar avatar={currentProfile?.avatar} size={50} /> <UserAvatar
avatar={currentProfile?.avatar}
size={50}
type={currentProfile?.associated?.labeler ? 'labeler' : 'user'}
/>
<TextInput <TextInput
ref={textInput} ref={textInput}
richtext={richtext} richtext={richtext}

View File

@ -87,6 +87,7 @@ export function ComposerReplyTo({replyTo}: {replyTo: ComposerOptsPostRef}) {
avatar={replyTo.author.avatar} avatar={replyTo.author.avatar}
size={50} size={50}
moderation={replyTo.moderation?.ui('avatar')} moderation={replyTo.moderation?.ui('avatar')}
type={replyTo.author.associated?.labeler ? 'labeler' : 'user'}
/> />
<View style={styles.replyToPost}> <View style={styles.replyToPost}>
<Text type="xl-medium" style={[pal.text]}> <Text type="xl-medium" style={[pal.text]}>

View File

@ -23,7 +23,11 @@ export function ComposePrompt({onPressCompose}: {onPressCompose: () => void}) {
accessibilityRole="button" accessibilityRole="button"
accessibilityLabel={_(msg`Compose reply`)} accessibilityLabel={_(msg`Compose reply`)}
accessibilityHint={_(msg`Opens composer`)}> accessibilityHint={_(msg`Opens composer`)}>
<UserAvatar avatar={profile?.avatar} size={38} /> <UserAvatar
avatar={profile?.avatar}
size={38}
type={profile?.associated?.labeler ? 'labeler' : 'user'}
/>
<Text <Text
type="xl" type="xl"
style={[ style={[

View File

@ -78,7 +78,11 @@ export function Autocomplete({
accessibilityLabel={`Select ${item.handle}`} accessibilityLabel={`Select ${item.handle}`}
accessibilityHint=""> accessibilityHint="">
<View style={styles.avatarAndHandle}> <View style={styles.avatarAndHandle}>
<UserAvatar avatar={item.avatar ?? null} size={24} /> <UserAvatar
avatar={item.avatar ?? null}
size={24}
type={item.associated?.labeler ? 'labeler' : 'user'}
/>
<Text type="md-medium" style={pal.text}> <Text type="md-medium" style={pal.text}>
{displayName} {displayName}
</Text> </Text>

View File

@ -175,7 +175,11 @@ const MentionList = forwardRef<MentionListRef, SuggestionProps>(
}} }}
accessibilityRole="button"> accessibilityRole="button">
<View style={styles.avatarAndDisplayName}> <View style={styles.avatarAndDisplayName}>
<UserAvatar avatar={item.avatar ?? null} size={26} /> <UserAvatar
avatar={item.avatar ?? null}
size={26}
type={item.associated?.labeler ? 'labeler' : 'user'}
/>
<Text style={pal.text} numberOfLines={1}> <Text style={pal.text} numberOfLines={1}>
{displayName} {displayName}
</Text> </Text>

View File

@ -231,7 +231,11 @@ function UserResult({
width: 54, width: 54,
paddingLeft: 4, paddingLeft: 4,
}}> }}>
<UserAvatar size={40} avatar={profile.avatar} /> <UserAvatar
size={40}
avatar={profile.avatar}
type={profile.associated?.labeler ? 'labeler' : 'user'}
/>
</View> </View>
<View <View
style={{ style={{

View File

@ -45,7 +45,11 @@ function SwitchAccountCard({account}: {account: SessionAccount}) {
const contents = ( const contents = (
<View style={[pal.view, styles.linkCard]}> <View style={[pal.view, styles.linkCard]}>
<View style={styles.avi}> <View style={styles.avi}>
<UserAvatar size={40} avatar={profile?.avatar} /> <UserAvatar
size={40}
avatar={profile?.avatar}
type={profile?.associated?.labeler ? 'labeler' : 'user'}
/>
</View> </View>
<View style={[s.flex1]}> <View style={[s.flex1]}>
<Text type="md-bold" style={pal.text} numberOfLines={1}> <Text type="md-bold" style={pal.text} numberOfLines={1}>

View File

@ -180,7 +180,7 @@ function ListItem({
}, },
]}> ]}>
<View style={styles.listItemAvi}> <View style={styles.listItemAvi}>
<UserAvatar size={40} avatar={list.avatar} /> <UserAvatar size={40} avatar={list.avatar} type="list" />
</View> </View>
<View style={styles.listItemContent}> <View style={styles.listItemContent}>
<Text <Text

View File

@ -14,6 +14,7 @@ import {
ModerationDecision, ModerationDecision,
moderateProfile, moderateProfile,
AppBskyEmbedRecordWithMedia, AppBskyEmbedRecordWithMedia,
AppBskyActorDefs,
} from '@atproto/api' } from '@atproto/api'
import {AtUri} from '@atproto/api' import {AtUri} from '@atproto/api'
import { import {
@ -55,6 +56,7 @@ interface Author {
displayName?: string displayName?: string
avatar?: string avatar?: string
moderation: ModerationDecision moderation: ModerationDecision
associated?: AppBskyActorDefs.ProfileAssociated
} }
let FeedItem = ({ let FeedItem = ({
@ -100,6 +102,7 @@ let FeedItem = ({
displayName: item.notification.author.displayName, displayName: item.notification.author.displayName,
avatar: item.notification.author.avatar, avatar: item.notification.author.avatar,
moderation: moderateProfile(item.notification.author, moderationOpts), moderation: moderateProfile(item.notification.author, moderationOpts),
associated: item.notification.author.associated,
}, },
...(item.additional?.map(({author}) => { ...(item.additional?.map(({author}) => {
return { return {
@ -109,6 +112,7 @@ let FeedItem = ({
displayName: author.displayName, displayName: author.displayName,
avatar: author.avatar, avatar: author.avatar,
moderation: moderateProfile(author, moderationOpts), moderation: moderateProfile(author, moderationOpts),
associated: author.associated,
} }
}) || []), }) || []),
] ]
@ -337,6 +341,7 @@ function CondensedAuthorsList({
handle={authors[0].handle} handle={authors[0].handle}
avatar={authors[0].avatar} avatar={authors[0].avatar}
moderation={authors[0].moderation.ui('avatar')} moderation={authors[0].moderation.ui('avatar')}
type={authors[0].associated?.labeler ? 'labeler' : 'user'}
/> />
</View> </View>
) )
@ -355,6 +360,7 @@ function CondensedAuthorsList({
size={35} size={35}
avatar={author.avatar} avatar={author.avatar}
moderation={author.moderation.ui('avatar')} moderation={author.moderation.ui('avatar')}
type={author.associated?.labeler ? 'labeler' : 'user'}
/> />
</View> </View>
))} ))}
@ -413,6 +419,7 @@ function ExpandedAuthorsList({
size={35} size={35}
avatar={author.avatar} avatar={author.avatar}
moderation={author.moderation.ui('avatar')} moderation={author.moderation.ui('avatar')}
type={author.associated?.labeler ? 'labeler' : 'user'}
/> />
</View> </View>
<View style={s.flex1}> <View style={s.flex1}>

View File

@ -205,11 +205,7 @@ let PostThreadItemLoaded = ({
uri: post.uri, uri: post.uri,
cid: post.cid, cid: post.cid,
text: record.text, text: record.text,
author: { author: post.author,
handle: post.author.handle,
displayName: post.author.displayName,
avatar: post.author.avatar,
},
embed: post.embed, embed: post.embed,
moderation, moderation,
}, },
@ -256,6 +252,7 @@ let PostThreadItemLoaded = ({
handle={post.author.handle} handle={post.author.handle}
avatar={post.author.avatar} avatar={post.author.avatar}
moderation={moderation.ui('avatar')} moderation={moderation.ui('avatar')}
type={post.author.associated?.labeler ? 'labeler' : 'user'}
/> />
</View> </View>
<View style={styles.layoutContent}> <View style={styles.layoutContent}>
@ -452,6 +449,7 @@ let PostThreadItemLoaded = ({
handle={post.author.handle} handle={post.author.handle}
avatar={post.author.avatar} avatar={post.author.avatar}
moderation={moderation.ui('avatar')} moderation={moderation.ui('avatar')}
type={post.author.associated?.labeler ? 'labeler' : 'user'}
/> />
{showChildReplyLine && ( {showChildReplyLine && (

View File

@ -118,11 +118,7 @@ function PostInner({
uri: post.uri, uri: post.uri,
cid: post.cid, cid: post.cid,
text: record.text, text: record.text,
author: { author: post.author,
handle: post.author.handle,
displayName: post.author.displayName,
avatar: post.author.avatar,
},
embed: post.embed, embed: post.embed,
moderation, moderation,
}, },
@ -144,6 +140,7 @@ function PostInner({
handle={post.author.handle} handle={post.author.handle}
avatar={post.author.avatar} avatar={post.author.avatar}
moderation={moderation.ui('avatar')} moderation={moderation.ui('avatar')}
type={post.author.associated?.labeler ? 'labeler' : 'user'}
/> />
</View> </View>
<View style={styles.layoutContent}> <View style={styles.layoutContent}>

View File

@ -126,11 +126,7 @@ let FeedItemInner = ({
uri: post.uri, uri: post.uri,
cid: post.cid, cid: post.cid,
text: record.text || '', text: record.text || '',
author: { author: post.author,
handle: post.author.handle,
displayName: post.author.displayName,
avatar: post.author.avatar,
},
embed: post.embed, embed: post.embed,
moderation, moderation,
}, },
@ -243,6 +239,7 @@ let FeedItemInner = ({
handle={post.author.handle} handle={post.author.handle}
avatar={post.author.avatar} avatar={post.author.avatar}
moderation={moderation.ui('avatar')} moderation={moderation.ui('avatar')}
type={post.author.associated?.labeler ? 'labeler' : 'user'}
/> />
{isThreadParent && ( {isThreadParent && (
<View <View

View File

@ -49,6 +49,7 @@ export function ProfileCard({
const pal = usePalette('default') const pal = usePalette('default')
const profile = useProfileShadow(profileUnshadowed) const profile = useProfileShadow(profileUnshadowed)
const moderationOpts = useModerationOpts() const moderationOpts = useModerationOpts()
const isLabeler = profile?.associated?.labeler
if (!moderationOpts) { if (!moderationOpts) {
return null return null
} }
@ -79,6 +80,7 @@ export function ProfileCard({
size={40} size={40}
avatar={profile.avatar} avatar={profile.avatar}
moderation={moderation.ui('avatar')} moderation={moderation.ui('avatar')}
type={isLabeler ? 'labeler' : 'user'}
/> />
</View> </View>
<View style={styles.layoutContent}> <View style={styles.layoutContent}>
@ -101,7 +103,7 @@ export function ProfileCard({
/> />
{!!profile.viewer?.followedBy && <View style={s.flexRow} />} {!!profile.viewer?.followedBy && <View style={s.flexRow} />}
</View> </View>
{renderButton ? ( {renderButton && !isLabeler ? (
<View style={styles.layoutButton}>{renderButton(profile)}</View> <View style={styles.layoutButton}>{renderButton(profile)}</View>
) : undefined} ) : undefined}
</View> </View>
@ -223,6 +225,7 @@ function FollowersList({
avatar={f.avatar} avatar={f.avatar}
size={32} size={32}
moderation={mod.ui('avatar')} moderation={mod.ui('avatar')}
type={f.associated?.labeler ? 'labeler' : 'user'}
/> />
</View> </View>
</View> </View>

View File

@ -98,9 +98,11 @@ export function ProfileHeaderSuggestedFollows({
<SuggestedFollowSkeleton /> <SuggestedFollowSkeleton />
</> </>
) : data ? ( ) : data ? (
data.suggestions.map(profile => ( data.suggestions
<SuggestedFollow key={profile.did} profile={profile} /> .filter(s => (s.associated?.labeler ? false : true))
)) .map(profile => (
<SuggestedFollow key={profile.did} profile={profile} />
))
) : ( ) : (
<View /> <View />
)} )}

View File

@ -11,16 +11,11 @@ import {sanitizeHandle} from 'lib/strings/handles'
import {isAndroid, isWeb} from 'platform/detection' import {isAndroid, isWeb} from 'platform/detection'
import {TimeElapsed} from './TimeElapsed' import {TimeElapsed} from './TimeElapsed'
import {makeProfileLink} from 'lib/routes/links' import {makeProfileLink} from 'lib/routes/links'
import {ModerationDecision, ModerationUI} from '@atproto/api' import {AppBskyActorDefs, ModerationDecision, ModerationUI} from '@atproto/api'
import {usePrefetchProfileQuery} from '#/state/queries/profile' import {usePrefetchProfileQuery} from '#/state/queries/profile'
interface PostMetaOpts { interface PostMetaOpts {
author: { author: AppBskyActorDefs.ProfileViewBasic
avatar?: string
did: string
handle: string
displayName?: string | undefined
}
moderation: ModerationDecision | undefined moderation: ModerationDecision | undefined
authorHasWarning: boolean authorHasWarning: boolean
postHref: string postHref: string
@ -47,6 +42,7 @@ let PostMeta = (opts: PostMetaOpts): React.ReactNode => {
avatar={opts.author.avatar} avatar={opts.author.avatar}
size={opts.avatarSize || 16} size={opts.avatarSize || 16}
moderation={opts.avatarModeration} moderation={opts.avatarModeration}
type={opts.author.associated?.labeler ? 'labeler' : 'user'}
/> />
</View> </View>
)} )}

View File

@ -59,11 +59,7 @@ export function PostThreadScreen({route}: Props) {
uri: thread.post.uri, uri: thread.post.uri,
cid: thread.post.cid, cid: thread.post.cid,
text: thread.record.text, text: thread.record.text,
author: { author: thread.post.author,
handle: thread.post.author.handle,
displayName: thread.post.author.displayName,
avatar: thread.post.author.avatar,
},
embed: thread.post.embed, embed: thread.post.embed,
}, },
onPost: () => onPost: () =>

View File

@ -141,6 +141,7 @@ function SearchScreenSuggestedFollows() {
friends.slice(0, 4).map(friend => friends.slice(0, 4).map(friend =>
getSuggestedFollowsByActor(friend.did).then(foafsRes => { getSuggestedFollowsByActor(friend.did).then(foafsRes => {
for (const user of foafsRes.suggestions) { for (const user of foafsRes.suggestions) {
if (user.associated?.labeler) continue
friendsOfFriends.set(user.did, user) friendsOfFriends.set(user.did, user)
} }
}), }),

View File

@ -82,7 +82,11 @@ function SettingsAccountCard({account}: {account: SessionAccount}) {
const contents = ( const contents = (
<View style={[pal.view, styles.linkCard]}> <View style={[pal.view, styles.linkCard]}>
<View style={styles.avi}> <View style={styles.avi}>
<UserAvatar size={40} avatar={profile?.avatar} /> <UserAvatar
size={40}
avatar={profile?.avatar}
type={profile?.associated?.labeler ? 'labeler' : 'user'}
/>
</View> </View>
<View style={[s.flex1]}> <View style={[s.flex1]}>
<Text type="md-bold" style={pal.text}> <Text type="md-bold" style={pal.text}>

View File

@ -75,6 +75,7 @@ let DrawerProfileCard = ({
avatar={profile?.avatar} avatar={profile?.avatar}
// See https://github.com/bluesky-social/social-app/pull/1801: // See https://github.com/bluesky-social/social-app/pull/1801:
usePlainRNImage={true} usePlainRNImage={true}
type={profile?.associated?.labeler ? 'labeler' : 'user'}
/> />
<Text <Text
type="title-lg" type="title-lg"

View File

@ -229,6 +229,7 @@ export function BottomBar({navigation}: BottomTabBarProps) {
size={27} size={27}
// See https://github.com/bluesky-social/social-app/pull/1801: // See https://github.com/bluesky-social/social-app/pull/1801:
usePlainRNImage={true} usePlainRNImage={true}
type={profile?.associated?.labeler ? 'labeler' : 'user'}
/> />
</View> </View>
) : ( ) : (
@ -238,6 +239,7 @@ export function BottomBar({navigation}: BottomTabBarProps) {
size={28} size={28}
// See https://github.com/bluesky-social/social-app/pull/1801: // See https://github.com/bluesky-social/social-app/pull/1801:
usePlainRNImage={true} usePlainRNImage={true}
type={profile?.associated?.labeler ? 'labeler' : 'user'}
/> />
</View> </View>
)} )}

View File

@ -64,7 +64,11 @@ function ProfileCard() {
style={[styles.profileCard, !isDesktop && styles.profileCardTablet]} style={[styles.profileCard, !isDesktop && styles.profileCardTablet]}
title={_(msg`My Profile`)} title={_(msg`My Profile`)}
asAnchor> asAnchor>
<UserAvatar avatar={profile.avatar} size={size} /> <UserAvatar
avatar={profile.avatar}
size={size}
type={profile?.associated?.labeler ? 'labeler' : 'user'}
/>
</Link> </Link>
) : ( ) : (
<View style={[styles.profileCard, !isDesktop && styles.profileCardTablet]}> <View style={[styles.profileCard, !isDesktop && styles.profileCardTablet]}>

View File

@ -112,6 +112,7 @@ export function SearchProfileCard({
size={40} size={40}
avatar={profile.avatar} avatar={profile.avatar}
moderation={moderation.ui('avatar')} moderation={moderation.ui('avatar')}
type={profile.associated?.labeler ? 'labeler' : 'user'}
/> />
<View style={{flex: 1}}> <View style={{flex: 1}}>
<Text <Text

View File

@ -34,10 +34,10 @@
jsonpointer "^5.0.0" jsonpointer "^5.0.0"
leven "^3.1.0" leven "^3.1.0"
"@atproto/api@^0.12.0": "@atproto/api@^0.12.1":
version "0.12.0" version "0.12.1"
resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.12.0.tgz#69e52f8761dc7d76c675fa7284bd49240bb0df64" resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.12.1.tgz#3340cbbd6a51a8c2f3248dae55a01415ab71084e"
integrity sha512-nSWiad1Z6IC/oVFSVxD5gZLhkD+J4EW2CFqAqIhklJNc0cjFKdmf8D56Pac6Ktm1sJoM6TVZ8GEeuEG6bJS/aQ== integrity sha512-Grigs9neuQxytXr2yHq/IfNlgXQVptWDO9KTQr5FDmgMY4Zly2X7Sa99u9c1CW9auwUTbcd+yRFBNEtbA3n3qg==
dependencies: dependencies:
"@atproto/common-web" "^0.3.0" "@atproto/common-web" "^0.3.0"
"@atproto/lexicon" "^0.4.0" "@atproto/lexicon" "^0.4.0"