diff --git a/src/components/ModerationLabelPref/index.tsx b/src/components/ModerationLabelPref/index.tsx
index 96c219f083..f7aed47ed3 100644
--- a/src/components/ModerationLabelPref/index.tsx
+++ b/src/components/ModerationLabelPref/index.tsx
@@ -2,6 +2,7 @@ import React from 'react'
import {View} from 'react-native'
import {useLingui} from '@lingui/react'
import {msg} from '@lingui/macro'
+import {InterprettedLabelValueDefinition} from '@atproto/api'
import {useLabelStrings} from '#/lib/moderation/useLabelStrings'
@@ -10,21 +11,26 @@ import {Text} from '#/components/Typography'
import * as ToggleButton from '#/components/forms/ToggleButton'
export function ModerationLabelPref({
- label,
+ labelValueDefinition,
disabled,
}: {
- label: string
+ labelValueDefinition: InterprettedLabelValueDefinition
disabled?: boolean
}) {
+ console.log({labelValueDefinition})
const t = useTheme()
const {_} = useLingui()
const allLabelStrings = useLabelStrings()
- const labelStrings = allLabelStrings[label] || {
- general: {
- name: label,
- description: `Labeled "${label}"`,
- },
- }
+ const labelStrings = labelValueDefinition.locales[0] // TODO look up locale
+ ? labelValueDefinition.locales[0]
+ : labelValueDefinition.identifier in allLabelStrings
+ ? allLabelStrings[labelValueDefinition.identifier].general
+ : {
+ general: {
+ name: labelValueDefinition.identifier,
+ description: `Labeled "${labelValueDefinition.identifier}"`,
+ },
+ }
// TODO add onChange behavior when mod prefs are updated
@@ -46,16 +52,16 @@ export function ModerationLabelPref({
a.align_center,
]}>
- {labelStrings.general.name}
+ {labelStrings.name}
- {labelStrings.general.description}
+ {labelStrings.description}
{!disabled && (
{}}>
diff --git a/src/lib/moderation.ts b/src/lib/moderation.ts
index fa9b21c08a..944a528c96 100644
--- a/src/lib/moderation.ts
+++ b/src/lib/moderation.ts
@@ -1,5 +1,10 @@
import React from 'react'
-import {ModerationCause, ModerationUI, AppBskyLabelerDefs} from '@atproto/api'
+import {
+ ModerationCause,
+ ModerationUI,
+ InterprettedLabelValueDefinition,
+ LABELS,
+} from '@atproto/api'
import {sanitizeDisplayName} from '#/lib/strings/display-names'
import {sanitizeHandle} from '#/lib/strings/handles'
@@ -47,3 +52,17 @@ export function getModerationServiceTitle({
? sanitizeDisplayName(displayName)
: sanitizeHandle(handle, '@')
}
+
+export function lookupLabelValueDefinition(
+ labelValue: string,
+ customDefs: InterprettedLabelValueDefinition[] | undefined,
+): InterprettedLabelValueDefinition | undefined {
+ let def
+ if (!labelValue.startsWith('!') && customDefs) {
+ def = customDefs.find(d => d.identifier === labelValue)
+ }
+ if (!def) {
+ def = LABELS[labelValue as keyof typeof LABELS]
+ }
+ return def
+}
diff --git a/src/screens/Profile/Header/ProfileHeaderModerator.tsx b/src/screens/Profile/Header/ProfileHeaderLabeler.tsx
similarity index 92%
rename from src/screens/Profile/Header/ProfileHeaderModerator.tsx
rename to src/screens/Profile/Header/ProfileHeaderLabeler.tsx
index 14a0e05dfe..dbaeae315c 100644
--- a/src/screens/Profile/Header/ProfileHeaderModerator.tsx
+++ b/src/screens/Profile/Header/ProfileHeaderLabeler.tsx
@@ -38,16 +38,16 @@ import {
interface Props {
profile: AppBskyActorDefs.ProfileViewDetailed
- modservice: AppBskyLabelerDefs.LabelerViewDetailed
+ labeler: AppBskyLabelerDefs.LabelerViewDetailed
descriptionRT: RichTextAPI | null
moderationOpts: ModerationOpts
hideBackButton?: boolean
isPlaceholderProfile?: boolean
}
-let ProfileHeaderModerator = ({
+let ProfileHeaderLabeler = ({
profile: profileUnshadowed,
- modservice,
+ labeler,
descriptionRT,
moderationOpts,
hideBackButton = false,
@@ -74,12 +74,12 @@ let ProfileHeaderModerator = ({
const {mutateAsync: unlikeMod, isPending: isUnlikePending} =
useUnlikeMutation()
const [likeUri, setLikeUri] = React.useState(
- modservice.viewer?.like || '',
+ labeler.viewer?.like || '',
)
const isLiked = !!likeUri
const onToggleLiked = React.useCallback(async () => {
- if (!modservice) {
+ if (!labeler) {
return
}
try {
@@ -90,7 +90,7 @@ let ProfileHeaderModerator = ({
track('CustomFeed:Unlike')
setLikeUri('')
} else {
- const res = await likeMod({uri: modservice.uri, cid: modservice.cid})
+ const res = await likeMod({uri: labeler.uri, cid: labeler.cid})
track('CustomFeed:Like')
setLikeUri(res.uri)
}
@@ -102,7 +102,7 @@ let ProfileHeaderModerator = ({
)
logger.error(`Failed to toggle labeler like`, {message: e.message})
}
- }, [modservice, likeUri, isLiked, likeMod, unlikeMod, track, _])
+ }, [labeler, likeUri, isLiked, likeMod, unlikeMod, track, _])
const onPressEditProfile = React.useCallback(() => {
track('ProfileHeader:EditProfileButtonClicked')
@@ -213,13 +213,13 @@ let ProfileHeaderModerator = ({
)}
- {typeof modservice.likeCount === 'number' && (
+ {typeof labeler.likeCount === 'number' && (
- Liked by {modservice.likeCount}{' '}
- {pluralize(modservice.likeCount, 'user')}
+ Liked by {labeler.likeCount}{' '}
+ {pluralize(labeler.likeCount, 'user')}
)}
@@ -230,5 +230,5 @@ let ProfileHeaderModerator = ({
)
}
-ProfileHeaderModerator = memo(ProfileHeaderModerator)
-export {ProfileHeaderModerator}
+ProfileHeaderLabeler = memo(ProfileHeaderLabeler)
+export {ProfileHeaderLabeler}
diff --git a/src/screens/Profile/Header/index.tsx b/src/screens/Profile/Header/index.tsx
index 669410eef7..1280dd8b10 100644
--- a/src/screens/Profile/Header/index.tsx
+++ b/src/screens/Profile/Header/index.tsx
@@ -10,7 +10,7 @@ import {LoadingPlaceholder} from 'view/com/util/LoadingPlaceholder'
import {usePalette} from 'lib/hooks/usePalette'
import {ProfileHeaderStandard} from './ProfileHeaderStandard'
-import {ProfileHeaderModerator} from './ProfileHeaderModerator'
+import {ProfileHeaderLabeler} from './ProfileHeaderLabeler'
let ProfileHeaderLoading = (_props: {}): React.ReactNode => {
const pal = usePalette('default')
@@ -34,7 +34,7 @@ export {ProfileHeaderLoading}
interface Props {
profile: AppBskyActorDefs.ProfileViewDetailed
- modservice: AppBskyLabelerDefs.LabelerViewDetailed | undefined
+ labeler: AppBskyLabelerDefs.LabelerViewDetailed | undefined
descriptionRT: RichTextAPI | null
moderationOpts: ModerationOpts
hideBackButton?: boolean
@@ -43,10 +43,10 @@ interface Props {
let ProfileHeader = (props: Props): React.ReactNode => {
if (props.profile.associated?.labeler) {
- if (!props.modservice) {
+ if (!props.labeler) {
return
}
- return
+ return
}
return
}
diff --git a/src/screens/Profile/Sections/ContentFilters.tsx b/src/screens/Profile/Sections/Labels.tsx
similarity index 53%
rename from src/screens/Profile/Sections/ContentFilters.tsx
rename to src/screens/Profile/Sections/Labels.tsx
index ac273dd8e0..5338def58a 100644
--- a/src/screens/Profile/Sections/ContentFilters.tsx
+++ b/src/screens/Profile/Sections/Labels.tsx
@@ -1,12 +1,18 @@
import React from 'react'
import {View} from 'react-native'
-import {AppBskyLabelerDefs, ModerationOpts} from '@atproto/api'
+import {
+ AppBskyLabelerDefs,
+ ModerationOpts,
+ interpretLabelValueDefinitions,
+ InterprettedLabelValueDefinition,
+} from '@atproto/api'
import {Trans, msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {useSafeAreaFrame} from 'react-native-safe-area-context'
import {useLabelerSubscriptionMutation} from '#/state/queries/labeler'
import {logger} from '#/logger'
+import {lookupLabelValueDefinition} from '#/lib/moderation'
import {useTheme, atoms as a} from '#/alf'
import {Text} from '#/components/Typography'
@@ -17,21 +23,20 @@ import {CenteredView, ScrollView} from '#/view/com/util/Views'
import {ErrorState} from '../ErrorState'
import {ModerationLabelPref} from '#/components/ModerationLabelPref'
-export function ProfileContentFiltersSection({
- modServiceQuery,
+export function ProfileLabelsSection({
+ isLabelerLoading,
+ labelerInfo,
+ labelerError,
moderationOpts,
}: {
- modServiceQuery: {
- data: AppBskyLabelerDefs.LabelerViewDetailed | undefined
- isLoading: boolean
- error: Error | null
- }
+ isLabelerLoading: boolean
+ labelerInfo: AppBskyLabelerDefs.LabelerViewDetailed | undefined
+ labelerError: Error | null
moderationOpts: ModerationOpts
}) {
const t = useTheme()
const {_} = useLingui()
const {height: minHeight} = useSafeAreaFrame()
- const {isLoading, error, data: modservice} = modServiceQuery
return (
- {isLoading ? (
+ {isLabelerLoading ? (
- ) : error || !modservice ? (
+ ) : labelerError || !labelerInfo ? (
) : (
-
)}
@@ -66,37 +71,46 @@ export function ProfileContentFiltersSection({
)
}
-export function ProfileContentFiltersSectionInner({
+export function ProfileLabelsSectionInner({
moderationOpts,
- modservice,
+ labelerInfo,
}: {
moderationOpts: ModerationOpts
- modservice: AppBskyLabelerDefs.LabelerViewDetailed
+ labelerInfo: AppBskyLabelerDefs.LabelerViewDetailed
}) {
const {_} = useLingui()
const t = useTheme()
const isEnabled = Boolean(
- moderationOpts.prefs.mods.find(mod => mod.did === modservice.creator.did),
+ moderationOpts.prefs.mods.find(mod => mod.did === labelerInfo.creator.did),
)
const hasSession = true // TODO
+ const {labelValues} = labelerInfo.policies
+ const labelDefs = React.useMemo(() => {
+ const customDefs = interpretLabelValueDefinitions(labelerInfo)
+ return labelValues
+ .map(val => lookupLabelValueDefinition(val, customDefs))
+ .filter(
+ def => def && def?.configurable,
+ ) as InterprettedLabelValueDefinition[]
+ }, [labelerInfo, labelValues])
const {mutateAsync: toggleSubscription, variables} =
useLabelerSubscriptionMutation()
const isSubscribed =
variables?.subscribe ??
- moderationOpts.prefs.mods.find(mod => mod.did === modservice.creator.did)
+ moderationOpts.prefs.mods.find(mod => mod.did === labelerInfo.creator.did)
const onPressSubscribe = React.useCallback(async () => {
try {
await toggleSubscription({
- did: modservice.creator.did,
+ did: labelerInfo.creator.did,
subscribe: !isSubscribed,
})
} catch (e: any) {
// setSubscriptionError(e.message)
logger.error(`Failed to subscribe to labeler`, {message: e.message})
}
- }, [toggleSubscription, isSubscribed, modservice])
+ }, [toggleSubscription, isSubscribed, labelerInfo])
return (
- {!isSubscribed && (
+ {labelValues.length === 0 ? (
- Subscribe to @{modservice.creator.handle} to use these labels:
+ This labeler hasn't declared what labels it publishes, and may not
+ be active.
- )}
-
-
- {
- undefined /* TODO modservice.policies.labelValues.map((def, i) => {
- return (
-
- {i !== 0 && }
-
-
- )
- })*/
- }
+ ) : !isSubscribed ? (
+
+
+ Subscribe to @{labelerInfo.creator.handle} to use these labels:
+
+
+ ) : null}
+ {labelDefs.length > 0 && (
+
+ {labelDefs.map((labelDef, i) => {
+ return (
+
+ {i !== 0 && }
+
+
+ )
+ })}
+
+ )}
diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx
index 0d795cab0b..2b0f01d733 100644
--- a/src/view/screens/Profile.tsx
+++ b/src/view/screens/Profile.tsx
@@ -37,7 +37,7 @@ import {listenSoftReset} from '#/state/events'
import {isInvalidHandle} from '#/lib/strings/handles'
import {ProfileFeedSection} from '#/screens/Profile/Sections/Feed'
-import {ProfileContentFiltersSection} from '#/screens/Profile/Sections/ContentFilters'
+import {ProfileLabelsSection} from '#/screens/Profile/Sections/Labels'
import {ProfileHeader, ProfileHeaderLoading} from '#/screens/Profile/Header'
interface SectionRef {
@@ -139,7 +139,11 @@ function ProfileScreenLoaded({
const setMinimalShellMode = useSetMinimalShellMode()
const {openComposer} = useComposerControls()
const {screen, track} = useAnalytics()
- const modServiceQuery = useLabelerInfoQuery({
+ const {
+ data: labelerInfo,
+ error: labelerError,
+ isLoading: isLabelerLoading,
+ } = useLabelerInfoQuery({
did: profile.did,
enabled: !!profile.associated?.labeler,
})
@@ -312,7 +316,7 @@ function ProfileScreenLoaded({
return (
{showFiltersTab
? ({headerHeight, isFocused, scrollElRef}) => (
-