Moderator variation of profile

This commit is contained in:
Paul Frazee
2024-02-27 16:55:31 -08:00
parent 697b262ba4
commit 05863426c5
9 changed files with 249 additions and 199 deletions
+66 -54
View File
@@ -152,75 +152,87 @@ export function ProfileHeaderDropdownBtn({
[currentAccount, profile],
)
const dropdownItems: DropdownItem[] = React.useMemo(() => {
let items: DropdownItem[] = [
{
testID: 'profileHeaderDropdownShareBtn',
label: isWeb ? _(msg`Copy link to profile`) : _(msg`Share`),
onPress: onPressShare,
let items: DropdownItem[] = []
if (hasSession && profile.associated?.modservice) {
items.push({
testID: 'profileHeaderDropdownFollowBtn',
label: _(msg`Follow Account`),
onPress: () => {}, // TODO
icon: {
ios: {
name: 'square.and.arrow.up',
name: 'plus',
},
android: 'ic_menu_share',
web: 'share',
android: '',
web: 'plus',
},
})
}
items.push({
testID: 'profileHeaderDropdownShareBtn',
label: isWeb ? _(msg`Copy Link to Profile`) : _(msg`Share`),
onPress: onPressShare,
icon: {
ios: {
name: 'square.and.arrow.up',
},
android: 'ic_menu_share',
web: 'share',
},
]
})
if (hasSession) {
if (!profile.associated?.modservice) {
items.push({label: 'separator'})
items.push({
testID: 'profileHeaderDropdownListAddRemoveBtn',
label: _(msg`Add to Lists`),
onPress: onPressAddRemoveLists,
icon: {
ios: {
name: 'list.bullet',
},
android: 'ic_menu_add',
web: 'list',
items.push({label: 'separator'})
items.push({
testID: 'profileHeaderDropdownListAddRemoveBtn',
label: _(msg`Add to Lists`),
onPress: onPressAddRemoveLists,
icon: {
ios: {
name: 'list.bullet',
},
})
if (!isMe) {
if (!profile.viewer?.blocking) {
if (!profile.viewer?.mutedByList) {
items.push({
testID: 'profileHeaderDropdownMuteBtn',
label: profile.viewer?.muted
? _(msg`Unmute Account`)
: _(msg`Mute Account`),
onPress: profile.viewer?.muted
? onPressUnmuteAccount
: onPressMuteAccount,
icon: {
ios: {
name: 'speaker.slash',
},
android: 'ic_lock_silent_mode',
web: 'comment-slash',
},
})
}
}
if (!profile.viewer?.blockingByList) {
android: 'ic_menu_add',
web: 'list',
},
})
if (!isMe) {
if (!profile.viewer?.blocking) {
if (!profile.viewer?.mutedByList) {
items.push({
testID: 'profileHeaderDropdownBlockBtn',
label: profile.viewer?.blocking
? _(msg`Unblock Account`)
: _(msg`Block Account`),
onPress: profile.viewer?.blocking
? onPressUnblockAccount
: onPressBlockAccount,
testID: 'profileHeaderDropdownMuteBtn',
label: profile.viewer?.muted
? _(msg`Unmute Account`)
: _(msg`Mute Account`),
onPress: profile.viewer?.muted
? onPressUnmuteAccount
: onPressMuteAccount,
icon: {
ios: {
name: 'person.fill.xmark',
name: 'speaker.slash',
},
android: 'ic_menu_close_clear_cancel',
web: 'user-slash',
android: 'ic_lock_silent_mode',
web: 'comment-slash',
},
})
}
}
if (!profile.viewer?.blockingByList) {
items.push({
testID: 'profileHeaderDropdownBlockBtn',
label: profile.viewer?.blocking
? _(msg`Unblock Account`)
: _(msg`Block Account`),
onPress: profile.viewer?.blocking
? onPressUnblockAccount
: onPressBlockAccount,
icon: {
ios: {
name: 'person.fill.xmark',
},
android: 'ic_menu_close_clear_cancel',
web: 'user-slash',
},
})
}
}
items.push({
testID: 'profileHeaderDropdownReportBtn',
+63
View File
@@ -0,0 +1,63 @@
import React from 'react'
import {View} from 'react-native'
import {AppBskyActorDefs} from '@atproto/api'
import {Trans, msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {Shadow} from '#/state/cache/types'
import {pluralize} from '#/lib/strings/helpers'
import {makeProfileLink} from 'lib/routes/links'
import {formatCount} from 'view/com/util/numeric/format'
import {atoms as a, useTheme} from '#/alf'
import {Text} from '#/components/Typography'
import {InlineLink} from '#/components/Link'
export function ProfileHeaderMetrics({
profile,
}: {
profile: Shadow<AppBskyActorDefs.ProfileViewDetailed>
}) {
const t = useTheme()
const {_} = useLingui()
const following = formatCount(profile.followsCount || 0)
const followers = formatCount(profile.followersCount || 0)
const pluralizedFollowers = pluralize(profile.followersCount || 0, 'follower')
return (
<View
style={[a.flex_row, a.gap_sm, a.align_center, a.pb_md]}
pointerEvents="box-none">
<InlineLink
testID="profileHeaderFollowersButton"
style={a.flex_row}
to={makeProfileLink(profile, 'followers')}
label={`${followers} ${pluralizedFollowers}`}>
<Text style={[a.font_bold, t.atoms.text, a.text_md]}>{followers} </Text>
<Text style={[t.atoms.text_contrast_medium, a.text_md]}>
{pluralizedFollowers}
</Text>
</InlineLink>
<InlineLink
testID="profileHeaderFollowsButton"
style={a.flex_row}
to={makeProfileLink(profile, 'follows')}
label={_(msg`${following} following`)}>
<Trans>
<Text style={[a.font_bold, t.atoms.text, a.text_md]}>
{following}{' '}
</Text>
<Text style={[t.atoms.text_contrast_medium, a.text_md]}>
following
</Text>
</Trans>
</InlineLink>
<Text style={[a.font_bold, t.atoms.text, a.text_md]}>
{formatCount(profile.postsCount || 0)}{' '}
<Text style={[t.atoms.text_contrast_medium, a.font_normal, a.text_md]}>
{pluralize(profile.postsCount || 0, 'post')}
</Text>
</Text>
</View>
)
}
@@ -30,6 +30,7 @@ import {ProfileHeaderShell} from './Shell'
import {ProfileHeaderDropdownBtn} from './DropdownBtn'
import {ProfileHeaderDisplayName} from './DisplayName'
import {ProfileHeaderHandle} from './Handle'
import {ProfileHeaderMetrics} from './Metrics'
import {
Heart2_Stroke2_Corner0_Rounded as Heart,
Heart2_Filled_Stroke2_Corner0_Rounded as HeartFilled,
@@ -170,7 +171,7 @@ let ProfileHeaderModerator = ({
{isSubscribed ? (
<Trans>Unsubscribe</Trans>
) : (
<Trans>Subscribe</Trans>
<Trans>Subscribe to labeler</Trans>
)}
</ButtonText>
</Button>
@@ -184,7 +185,18 @@ let ProfileHeaderModerator = ({
</View>
{!isPlaceholderProfile && (
<>
<View style={[a.flex_row, a.gap_md, a.align_center, a.pb_md]}>
<ProfileHeaderMetrics profile={profile} />
{descriptionRT && !moderation.ui('profileView').blur ? (
<View pointerEvents="auto">
<RichText
testID="profileHeaderDescription"
style={t.atoms.text}
numberOfLines={15}
richText={descriptionRT}
/>
</View>
) : undefined}
<View style={[a.flex_row, a.gap_md, a.align_center, a.pt_md]}>
<Button
testID="toggleLikeBtn"
size="small"
@@ -212,16 +224,6 @@ let ProfileHeaderModerator = ({
</InlineLink>
)}
</View>
{descriptionRT && !moderation.ui('profileView').blur ? (
<View pointerEvents="auto">
<RichText
testID="profileHeaderDescription"
style={t.atoms.text}
numberOfLines={15}
richText={descriptionRT}
/>
</View>
) : undefined}
</>
)}
</View>
@@ -20,20 +20,16 @@ import {
useProfileBlockMutationQueue,
} from '#/state/queries/profile'
import {logger} from '#/logger'
import {pluralize} from '#/lib/strings/helpers'
import {makeProfileLink} from 'lib/routes/links'
import {formatCount} from 'view/com/util/numeric/format'
import {sanitizeDisplayName} from 'lib/strings/display-names'
import {atoms as a, useTheme} from '#/alf'
import {Text} from '#/components/Typography'
import {InlineLink} from '#/components/Link'
import {Button, ButtonText, ButtonIcon} from '#/components/Button'
import * as Toast from '#/view/com/util/Toast'
import {ProfileHeaderShell} from './Shell'
import {ProfileHeaderDropdownBtn} from './DropdownBtn'
import {ProfileHeaderDisplayName} from './DisplayName'
import {ProfileHeaderHandle} from './Handle'
import {ProfileHeaderMetrics} from './Metrics'
import {ProfileHeaderSuggestedFollows} from '#/view/com/profile/ProfileHeaderSuggestedFollows'
import {RichText} from 'view/com/util/text/RichText'
import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
@@ -146,9 +142,6 @@ let ProfileHeaderStandard = ({
() => currentAccount?.did === profile.did,
[currentAccount, profile],
)
const following = formatCount(profile.followsCount || 0)
const followers = formatCount(profile.followersCount || 0)
const pluralizedFollowers = pluralize(profile.followersCount || 0, 'follower')
return (
<ProfileHeaderShell
@@ -249,47 +242,7 @@ let ProfileHeaderStandard = ({
</View>
{!isPlaceholderProfile && (
<>
<View
style={[a.flex_row, a.gap_sm, a.align_center, a.pb_md]}
pointerEvents="box-none">
<InlineLink
testID="profileHeaderFollowersButton"
style={a.flex_row}
to={makeProfileLink(profile, 'followers')}
label={`${followers} ${pluralizedFollowers}`}>
<Text style={[a.font_bold, t.atoms.text, a.text_md]}>
{followers}{' '}
</Text>
<Text style={[t.atoms.text_contrast_medium, a.text_md]}>
{pluralizedFollowers}
</Text>
</InlineLink>
<InlineLink
testID="profileHeaderFollowsButton"
style={a.flex_row}
to={makeProfileLink(profile, 'follows')}
label={_(msg`${following} following`)}>
<Trans>
<Text style={[a.font_bold, t.atoms.text, a.text_md]}>
{following}{' '}
</Text>
<Text style={[t.atoms.text_contrast_medium, a.text_md]}>
following
</Text>
</Trans>
</InlineLink>
<Text style={[a.font_bold, t.atoms.text, a.text_md]}>
{formatCount(profile.postsCount || 0)}{' '}
<Text
style={[
t.atoms.text_contrast_medium,
a.font_normal,
a.text_md,
]}>
{pluralize(profile.postsCount || 0, 'post')}
</Text>
</Text>
</View>
<ProfileHeaderMetrics profile={profile} />
{descriptionRT && !moderation.ui('profileView').blur ? (
<View pointerEvents="auto">
<RichText
+5
View File
@@ -113,8 +113,10 @@ let ProfileHeaderShell = ({
t.atoms.bg,
{borderColor: t.atoms.bg.backgroundColor},
styles.avi,
profile.associated?.modservice && styles.aviLabeler,
]}>
<UserAvatar
type={profile.associated?.modservice ? 'labeler' : 'user'}
size={90}
avatar={profile.avatar}
moderation={moderation.ui('avatar')}
@@ -155,4 +157,7 @@ const styles = StyleSheet.create({
borderRadius: 47,
borderWidth: 2,
},
aviLabeler: {
borderRadius: 12,
},
})
+6 -6
View File
@@ -42,12 +42,12 @@ interface Props {
}
let ProfileHeader = (props: Props): React.ReactNode => {
// if (props.profile.associated?.modservice) {
// if (!props.modservice) {
// return <ProfileHeaderLoading />
// }
// return <ProfileHeaderModerator {...props} modservice={props.modservice} />
// }
if (props.profile.associated?.modservice) {
if (!props.modservice) {
return <ProfileHeaderLoading />
}
return <ProfileHeaderModerator {...props} modservice={props.modservice} />
}
return <ProfileHeaderStandard {...props} />
}
ProfileHeader = memo(ProfileHeader)
+17 -42
View File
@@ -113,51 +113,26 @@ export function ProfileContentFiltersSectionInner({
borderWidth: 0,
paddingHorizontal: a.px_xl.paddingLeft,
}}>
<View style={[a.flex_row, a.gap_md, a.pt_xl]}>
<View style={[a.flex_1]}>
<Text style={[t.atoms.text_contrast_high, a.leading_snug, a.text_md]}>
<View style={[a.pt_xl]}>
<Text style={[t.atoms.text_contrast_high, a.leading_snug, a.text_sm]}>
<Trans>
Labels are annotations on users and content. They can be used to
hide, warn, and categorize the network.
</Trans>
</Text>
{!isSubscribed && (
<Text
style={[
a.pt_xl,
t.atoms.text_contrast_high,
a.leading_snug,
a.text_sm,
]}>
<Trans>
Labels are annotations on users and content. They can be used to
hide, warn, and categorize the network.
Subscribe to @{modservice.creator.handle} to use these labels:
</Trans>
</Text>
{!isSubscribed && (
<Text
style={[
a.pt_xl,
t.atoms.text_contrast_high,
a.leading_snug,
a.text_md,
]}>
<Trans>
Subscribe to use these labels from @{modservice.creator.handle}:
</Trans>
</Text>
)}
</View>
<View>
<Button
testID="toggleSubscribeBtn"
size="small"
color={isSubscribed ? 'secondary' : 'primary'}
variant="solid"
label={
isSubscribed
? _(msg`Unsubscribe from this labeler`)
: _(msg`Subscribe to this labeler`)
}
disabled={!hasSession}
onPress={onPressSubscribe}
style={a.rounded_full}>
<ButtonText>
{isSubscribed ? (
<Trans>Unsubscribe</Trans>
) : (
<Trans>Subscribe</Trans>
)}
</ButtonText>
</Button>
</View>
)}
</View>
<View
style={[