Implement new label config controls (wip)
This commit is contained in:
@@ -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 |
@@ -1,14 +1,14 @@
|
||||
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'
|
||||
import {useLabelBehaviorDescription} from '#/lib/moderation/useLabelBehaviorDescription'
|
||||
|
||||
import {useTheme, atoms as a} from '#/alf'
|
||||
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({
|
||||
labelValueDefinition,
|
||||
@@ -19,64 +19,42 @@ export function ModerationLabelPref({
|
||||
}) {
|
||||
console.log({labelValueDefinition})
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
const allLabelStrings = useLabelStrings()
|
||||
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}"`,
|
||||
},
|
||||
name: labelValueDefinition.identifier,
|
||||
description: `Labeled "${labelValueDefinition.identifier}"`,
|
||||
}
|
||||
const settingDesc = useLabelBehaviorDescription(labelValueDefinition, 'hide')
|
||||
|
||||
// TODO add onChange behavior when mod prefs are updated
|
||||
|
||||
const labelOptions = {
|
||||
hide: _(msg`Hide`),
|
||||
warn: _(msg`Warn`),
|
||||
show: _(msg`Ignore`),
|
||||
}
|
||||
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
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%'}]}>
|
||||
<View style={[a.flex_row, a.justify_between, a.gap_lg, a.align_center]}>
|
||||
<View style={[a.gap_xs, a.flex_1]}>
|
||||
<Text style={[a.font_bold]}>{labelStrings.name}</Text>
|
||||
<Text style={[t.atoms.text_contrast_medium, a.leading_snug]}>
|
||||
{labelStrings.description}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={[a.justify_center, {minHeight: 35}]}>
|
||||
{!disabled && (
|
||||
<ToggleButton.Group
|
||||
label={_(
|
||||
msg`Configure content filtering setting for category: ${labelStrings.name.toLowerCase()}`,
|
||||
)}
|
||||
values={['hide']}
|
||||
onChange={() => {}}>
|
||||
<ToggleButton.Button name="show" label={labelOptions.show}>
|
||||
{labelOptions.show}
|
||||
</ToggleButton.Button>
|
||||
<ToggleButton.Button name="warn" label={labelOptions.warn}>
|
||||
{labelOptions.warn}
|
||||
</ToggleButton.Button>
|
||||
<ToggleButton.Button name="hide" label={labelOptions.hide}>
|
||||
{labelOptions.hide}
|
||||
</ToggleButton.Button>
|
||||
</ToggleButton.Group>
|
||||
)}
|
||||
</View>
|
||||
{!disabled && (
|
||||
<View
|
||||
style={[
|
||||
a.flex_row,
|
||||
a.align_center,
|
||||
a.justify_end,
|
||||
a.gap_xs,
|
||||
{width: 125},
|
||||
]}>
|
||||
<Text style={[{color: t.palette.primary_500}, a.font_semibold]}>
|
||||
{settingDesc}
|
||||
</Text>
|
||||
<ArrowTriangleBottom width={8} fill={t.palette.primary_500} />
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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`)
|
||||
}
|
||||
}
|
||||
@@ -80,11 +80,10 @@ export function ProfileLabelsSectionInner({
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
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 isSubscribed = moderationOpts.prefs.mods.find(
|
||||
mod => mod.did === labelerInfo.creator.did,
|
||||
)
|
||||
const labelDefs = React.useMemo(() => {
|
||||
const customDefs = interpretLabelValueDefinitions(labelerInfo)
|
||||
return labelValues
|
||||
@@ -94,24 +93,6 @@ export function ProfileLabelsSectionInner({
|
||||
) as InterprettedLabelValueDefinition[]
|
||||
}, [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 (
|
||||
<ScrollView
|
||||
scrollEventThrottle={1}
|
||||
@@ -164,12 +145,14 @@ export function ProfileLabelsSectionInner({
|
||||
]}>
|
||||
{labelDefs.map((labelDef, i) => {
|
||||
return (
|
||||
<React.Fragment key={labelDef?.identifier}>
|
||||
<React.Fragment key={labelDef.identifier}>
|
||||
{i !== 0 && <Divider />}
|
||||
<ModerationLabelPref
|
||||
disabled={isEnabled ? undefined : true}
|
||||
labelValueDefinition={labelDef}
|
||||
/>
|
||||
<View style={[a.py_lg, a.px_md]}>
|
||||
<ModerationLabelPref
|
||||
disabled={isSubscribed ? undefined : true}
|
||||
labelValueDefinition={labelDef}
|
||||
/>
|
||||
</View>
|
||||
</React.Fragment>
|
||||
)
|
||||
})}
|
||||
|
||||
Reference in New Issue
Block a user