Implement new label config controls (wip)

This commit is contained in:
Paul Frazee
2024-03-04 16:00:15 -08:00
parent 4d0dc7438b
commit f99307033c
7 changed files with 116 additions and 72 deletions
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" d="M4.213 6.886c-.673-1.35.334-2.889 1.806-2.889H17.98c1.472 0 2.479 1.539 1.806 2.89l-5.982 11.997c-.74 1.484-2.87 1.484-3.61 0L4.213 6.886Z"/></svg>

After

Width:  |  Height:  |  Size: 240 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M12.86 4.494a.995.995 0 0 0-1.72 0L4.14 16.502A.996.996 0 0 0 4.999 18h14.003a.996.996 0 0 0 .86-1.498L12.86 4.494ZM9.413 3.487c1.155-1.983 4.019-1.983 5.174 0l7.002 12.007C22.753 17.491 21.314 20 19.002 20H4.998c-2.312 0-3.751-2.509-2.587-4.506L9.413 3.487ZM12 8.019a1 1 0 0 1 1 1v2.994a1 1 0 1 1-2 0V9.02a1 1 0 0 1 1-1Z" clip-rule="evenodd"/><rect width="2.5" height="2.5" x="10.75" y="13.75" fill="#000" rx="1.25"/></svg>

After

Width:  |  Height:  |  Size: 537 B

+19 -41
View File
@@ -1,14 +1,14 @@
import React from 'react' import React from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {useLingui} from '@lingui/react'
import {msg} from '@lingui/macro'
import {InterprettedLabelValueDefinition} from '@atproto/api' import {InterprettedLabelValueDefinition} from '@atproto/api'
import {useLabelStrings} from '#/lib/moderation/useLabelStrings' import {useLabelStrings} from '#/lib/moderation/useLabelStrings'
import {useLabelBehaviorDescription} from '#/lib/moderation/useLabelBehaviorDescription'
import {useTheme, atoms as a} from '#/alf' import {useTheme, atoms as a} from '#/alf'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
import * as ToggleButton from '#/components/forms/ToggleButton' import {Button, ButtonText, ButtonIcon} from '#/components/Button'
import {ArrowTriangleBottom_Stroke2_Corner1_Rounded as ArrowTriangleBottom} from '../icons/ArrowTriangle'
export function ModerationLabelPref({ export function ModerationLabelPref({
labelValueDefinition, labelValueDefinition,
@@ -19,64 +19,42 @@ export function ModerationLabelPref({
}) { }) {
console.log({labelValueDefinition}) console.log({labelValueDefinition})
const t = useTheme() const t = useTheme()
const {_} = useLingui()
const allLabelStrings = useLabelStrings() const allLabelStrings = useLabelStrings()
const labelStrings = labelValueDefinition.locales[0] // TODO look up locale const labelStrings = labelValueDefinition.locales[0] // TODO look up locale
? labelValueDefinition.locales[0] ? labelValueDefinition.locales[0]
: labelValueDefinition.identifier in allLabelStrings : labelValueDefinition.identifier in allLabelStrings
? allLabelStrings[labelValueDefinition.identifier].general ? allLabelStrings[labelValueDefinition.identifier].general
: { : {
general: {
name: labelValueDefinition.identifier, name: labelValueDefinition.identifier,
description: `Labeled "${labelValueDefinition.identifier}"`, description: `Labeled "${labelValueDefinition.identifier}"`,
},
} }
const settingDesc = useLabelBehaviorDescription(labelValueDefinition, 'hide')
// TODO add onChange behavior when mod prefs are updated // TODO add onChange behavior when mod prefs are updated
const labelOptions = {
hide: _(msg`Hide`),
warn: _(msg`Warn`),
show: _(msg`Ignore`),
}
return ( return (
<View <View style={[a.flex_row, a.justify_between, a.gap_lg, a.align_center]}>
style={[ <View style={[a.gap_xs, a.flex_1]}>
a.flex_row,
a.justify_between,
a.gap_sm,
a.py_md,
a.pl_lg,
a.pr_md,
a.align_center,
]}>
<View style={[a.gap_xs, {width: '50%'}]}>
<Text style={[a.font_bold]}>{labelStrings.name}</Text> <Text style={[a.font_bold]}>{labelStrings.name}</Text>
<Text style={[t.atoms.text_contrast_medium, a.leading_snug]}> <Text style={[t.atoms.text_contrast_medium, a.leading_snug]}>
{labelStrings.description} {labelStrings.description}
</Text> </Text>
</View> </View>
<View style={[a.justify_center, {minHeight: 35}]}>
{!disabled && ( {!disabled && (
<ToggleButton.Group <View
label={_( style={[
msg`Configure content filtering setting for category: ${labelStrings.name.toLowerCase()}`, a.flex_row,
)} a.align_center,
values={['hide']} a.justify_end,
onChange={() => {}}> a.gap_xs,
<ToggleButton.Button name="show" label={labelOptions.show}> {width: 125},
{labelOptions.show} ]}>
</ToggleButton.Button> <Text style={[{color: t.palette.primary_500}, a.font_semibold]}>
<ToggleButton.Button name="warn" label={labelOptions.warn}> {settingDesc}
{labelOptions.warn} </Text>
</ToggleButton.Button> <ArrowTriangleBottom width={8} fill={t.palette.primary_500} />
<ToggleButton.Button name="hide" label={labelOptions.hide}>
{labelOptions.hide}
</ToggleButton.Button>
</ToggleButton.Group>
)}
</View> </View>
)}
</View> </View>
) )
} }
+5
View File
@@ -0,0 +1,5 @@
import {createSinglePathSVG} from './TEMPLATE'
export const ArrowTriangleBottom_Stroke2_Corner1_Rounded = createSinglePathSVG({
path: 'M4.213 6.886c-.673-1.35.334-2.889 1.806-2.889H17.98c1.472 0 2.479 1.539 1.806 2.89l-5.982 11.997c-.74 1.484-2.87 1.484-3.61 0L4.213 6.886Z',
})
@@ -0,0 +1,37 @@
import React from 'react'
import Svg, {Path, Rect} from 'react-native-svg'
import {useCommonSVGProps, Props} from '#/components/icons/common'
export const TriangleExclamation_Stroke2_Corner2_Rounded = React.forwardRef<
Svg,
Props
>(function LogoImpl(props, ref) {
const {fill, size, style, ...rest} = useCommonSVGProps(props)
return (
<Svg
fill="none"
{...rest}
ref={ref}
viewBox="0 0 24 24"
width={size}
height={size}
style={[style]}>
<Path
fill={fill}
fillRule="evenodd"
clipRule="evenodd"
d="M12.86 4.494a.995.995 0 0 0-1.72 0L4.14 16.502A.996.996 0 0 0 4.999 18h14.003a.996.996 0 0 0 .86-1.498L12.86 4.494ZM9.413 3.487c1.155-1.983 4.019-1.983 5.174 0l7.002 12.007C22.753 17.491 21.314 20 19.002 20H4.998c-2.312 0-3.751-2.509-2.587-4.506L9.413 3.487ZM12 8.019a1 1 0 0 1 1 1v2.994a1 1 0 1 1-2 0V9.02a1 1 0 0 1 1-1Z"
/>
<Rect
width="2.5"
height="2.5"
x="10.75"
y="13.75"
fill={fill}
rx="1.25"
/>
</Svg>
)
})
@@ -0,0 +1,39 @@
import {InterprettedLabelValueDefinition, LabelPreference} from '@atproto/api'
import {useLingui} from '@lingui/react'
import {msg} from '@lingui/macro'
export function useLabelBehaviorDescription(
labelValueDef: InterprettedLabelValueDefinition,
pref: LabelPreference,
) {
const {_} = useLingui()
if (pref === 'ignore') {
return _(msg`Disabled`)
}
if (labelValueDef.blurs === 'content') {
if (pref === 'hide') {
return _(msg`Hide content`)
}
return _(msg`Warn content`)
} else if (labelValueDef.blurs === 'media') {
if (pref === 'hide') {
return _(msg`Hide images`)
}
return _(msg`Warn images`)
} else if (labelValueDef.severity === 'alert') {
if (pref === 'hide') {
return _(msg`Filter from feeds`)
}
return _(msg`Show warning`)
} else if (labelValueDef.severity === 'inform') {
if (pref === 'hide') {
return _(msg`Filter from feeds`)
}
return _(msg`Show badge`)
} else {
if (pref === 'hide') {
return _(msg`Filter from feeds`)
}
return _(msg`Disabled`)
}
}
+7 -24
View File
@@ -80,11 +80,10 @@ export function ProfileLabelsSectionInner({
}) { }) {
const {_} = useLingui() const {_} = useLingui()
const t = useTheme() const t = useTheme()
const isEnabled = Boolean(
moderationOpts.prefs.mods.find(mod => mod.did === labelerInfo.creator.did),
)
const hasSession = true // TODO
const {labelValues} = labelerInfo.policies const {labelValues} = labelerInfo.policies
const isSubscribed = moderationOpts.prefs.mods.find(
mod => mod.did === labelerInfo.creator.did,
)
const labelDefs = React.useMemo(() => { const labelDefs = React.useMemo(() => {
const customDefs = interpretLabelValueDefinitions(labelerInfo) const customDefs = interpretLabelValueDefinitions(labelerInfo)
return labelValues return labelValues
@@ -94,24 +93,6 @@ export function ProfileLabelsSectionInner({
) as InterprettedLabelValueDefinition[] ) as InterprettedLabelValueDefinition[]
}, [labelerInfo, labelValues]) }, [labelerInfo, labelValues])
const {mutateAsync: toggleSubscription, variables} =
useLabelerSubscriptionMutation()
const isSubscribed =
variables?.subscribe ??
moderationOpts.prefs.mods.find(mod => mod.did === labelerInfo.creator.did)
const onPressSubscribe = React.useCallback(async () => {
try {
await toggleSubscription({
did: labelerInfo.creator.did,
subscribe: !isSubscribed,
})
} catch (e: any) {
// setSubscriptionError(e.message)
logger.error(`Failed to subscribe to labeler`, {message: e.message})
}
}, [toggleSubscription, isSubscribed, labelerInfo])
return ( return (
<ScrollView <ScrollView
scrollEventThrottle={1} scrollEventThrottle={1}
@@ -164,12 +145,14 @@ export function ProfileLabelsSectionInner({
]}> ]}>
{labelDefs.map((labelDef, i) => { {labelDefs.map((labelDef, i) => {
return ( return (
<React.Fragment key={labelDef?.identifier}> <React.Fragment key={labelDef.identifier}>
{i !== 0 && <Divider />} {i !== 0 && <Divider />}
<View style={[a.py_lg, a.px_md]}>
<ModerationLabelPref <ModerationLabelPref
disabled={isEnabled ? undefined : true} disabled={isSubscribed ? undefined : true}
labelValueDefinition={labelDef} labelValueDefinition={labelDef}
/> />
</View>
</React.Fragment> </React.Fragment>
) )
})} })}