about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/ReportDialog/SelectLabelerView.tsx17
-rw-r--r--src/components/ReportDialog/SelectReportOptionView.tsx80
-rw-r--r--src/components/ReportDialog/index.tsx6
-rw-r--r--src/components/forms/TextField.tsx12
-rw-r--r--src/components/moderation/GlobalModerationLabelPref.tsx93
-rw-r--r--src/components/moderation/LabelPreference.tsx294
-rw-r--r--src/components/moderation/ModerationLabelPref.tsx177
-rw-r--r--src/screens/Moderation/index.tsx12
-rw-r--r--src/screens/Profile/Sections/Labels.tsx6
-rw-r--r--src/view/com/auth/SplashScreen.tsx18
-rw-r--r--src/view/com/auth/SplashScreen.web.tsx19
-rw-r--r--src/view/com/post-thread/PostThread.tsx32
12 files changed, 388 insertions, 378 deletions
diff --git a/src/components/ReportDialog/SelectLabelerView.tsx b/src/components/ReportDialog/SelectLabelerView.tsx
index 817426355..383d1b95f 100644
--- a/src/components/ReportDialog/SelectLabelerView.tsx
+++ b/src/components/ReportDialog/SelectLabelerView.tsx
@@ -38,7 +38,7 @@ export function SelectLabelerView({
 
       <Divider />
 
-      <View style={[a.gap_xs, {marginHorizontal: a.p_md.padding * -1}]}>
+      <View style={[a.gap_sm]}>
         {props.labelers.map(labeler => {
           return (
             <Button
@@ -63,17 +63,14 @@ function LabelerButton({
   const {hovered, pressed} = useButtonContext()
   const interacted = hovered || pressed
 
-  const styles = React.useMemo(() => {
-    return {
-      interacted: {
-        backgroundColor: t.palette.contrast_50,
-      },
-    }
-  }, [t])
-
   return (
     <LabelingServiceCard.Outer
-      style={[a.p_md, a.rounded_sm, interacted && styles.interacted]}>
+      style={[
+        a.p_md,
+        a.rounded_sm,
+        t.atoms.bg_contrast_25,
+        interacted && t.atoms.bg_contrast_50,
+      ]}>
       <LabelingServiceCard.Avatar avatar={labeler.creator.avatar} />
       <LabelingServiceCard.Content>
         <LabelingServiceCard.Title
diff --git a/src/components/ReportDialog/SelectReportOptionView.tsx b/src/components/ReportDialog/SelectReportOptionView.tsx
index bacf5a867..54844cfda 100644
--- a/src/components/ReportDialog/SelectReportOptionView.tsx
+++ b/src/components/ReportDialog/SelectReportOptionView.tsx
@@ -86,7 +86,7 @@ export function SelectReportOptionView({
 
       <Divider />
 
-      <View style={[a.gap_sm, {marginHorizontal: a.p_md.padding * -1}]}>
+      <View style={[a.gap_sm]}>
         {reportOptions.map(reportOption => {
           return (
             <Button
@@ -102,39 +102,37 @@ export function SelectReportOptionView({
         })}
 
         {(props.params.type === 'post' || props.params.type === 'account') && (
-          <View style={[a.pt_md, a.px_md]}>
-            <View
+          <View
+            style={[
+              a.flex_row,
+              a.align_center,
+              a.justify_between,
+              a.gap_lg,
+              a.p_md,
+              a.pl_lg,
+              a.rounded_md,
+              t.atoms.bg_contrast_900,
+            ]}>
+            <Text
               style={[
-                a.flex_row,
-                a.align_center,
-                a.justify_between,
-                a.gap_lg,
-                a.p_md,
-                a.pl_lg,
-                a.rounded_md,
-                t.atoms.bg_contrast_900,
+                a.flex_1,
+                t.atoms.text_inverted,
+                a.italic,
+                a.leading_snug,
               ]}>
-              <Text
-                style={[
-                  a.flex_1,
-                  t.atoms.text_inverted,
-                  a.italic,
-                  a.leading_snug,
-                ]}>
-                <Trans>Need to report a copyright violation?</Trans>
-              </Text>
-              <Link
-                to={DMCA_LINK}
-                label={_(msg`View details for reporting a copyright violation`)}
-                size="small"
-                variant="solid"
-                color="secondary">
-                <ButtonText>
-                  <Trans>View details</Trans>
-                </ButtonText>
-                <ButtonIcon position="right" icon={SquareArrowTopRight} />
-              </Link>
-            </View>
+              <Trans>Need to report a copyright violation?</Trans>
+            </Text>
+            <Link
+              to={DMCA_LINK}
+              label={_(msg`View details for reporting a copyright violation`)}
+              size="small"
+              variant="solid"
+              color="secondary">
+              <ButtonText>
+                <Trans>View details</Trans>
+              </ButtonText>
+              <ButtonIcon position="right" icon={SquareArrowTopRight} />
+            </Link>
           </View>
         )}
       </View>
@@ -153,14 +151,6 @@ function ReportOptionButton({
   const {hovered, pressed} = useButtonContext()
   const interacted = hovered || pressed
 
-  const styles = React.useMemo(() => {
-    return {
-      interacted: {
-        backgroundColor: t.palette.contrast_50,
-      },
-    }
-  }, [t])
-
   return (
     <View
       style={[
@@ -171,7 +161,8 @@ function ReportOptionButton({
         a.p_md,
         a.rounded_md,
         {paddingRight: 70},
-        interacted && styles.interacted,
+        t.atoms.bg_contrast_25,
+        interacted && t.atoms.bg_contrast_50,
       ]}>
       <View style={[a.flex_1, a.gap_xs]}>
         <Text style={[a.text_md, a.font_bold, t.atoms.text_contrast_medium]}>
@@ -188,12 +179,7 @@ function ReportOptionButton({
           a.pr_md,
           {left: 'auto'},
         ]}>
-        <ChevronRight
-          size="md"
-          fill={
-            hovered ? t.palette.primary_500 : t.atoms.text_contrast_low.color
-          }
-        />
+        <ChevronRight size="md" fill={t.atoms.text_contrast_low.color} />
       </View>
     </View>
   )
diff --git a/src/components/ReportDialog/index.tsx b/src/components/ReportDialog/index.tsx
index b41df3b3a..c87d32f9e 100644
--- a/src/components/ReportDialog/index.tsx
+++ b/src/components/ReportDialog/index.tsx
@@ -1,6 +1,7 @@
 import React from 'react'
 import {Pressable, View} from 'react-native'
-import {Trans} from '@lingui/macro'
+import {msg, Trans} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
 
 import {ReportOption} from '#/lib/moderation/useReportOptions'
 import {useMyLabelersQuery} from '#/state/queries/preferences'
@@ -31,6 +32,7 @@ export function ReportDialog(props: ReportDialogProps) {
 }
 
 function ReportDialogInner(props: ReportDialogProps) {
+  const {_} = useLingui()
   const {
     isLoading: isLabelerLoading,
     data: labelers,
@@ -44,7 +46,7 @@ function ReportDialogInner(props: ReportDialogProps) {
   })
 
   return (
-    <Dialog.ScrollableInner label="Report Dialog" ref={ref}>
+    <Dialog.ScrollableInner label={_(msg`Report dialog`)} ref={ref}>
       {isLoading ? (
         <View style={[a.align_center, {height: 100}]}>
           <Loader size="xl" />
diff --git a/src/components/forms/TextField.tsx b/src/components/forms/TextField.tsx
index 376883c9d..0bdeca645 100644
--- a/src/components/forms/TextField.tsx
+++ b/src/components/forms/TextField.tsx
@@ -1,20 +1,20 @@
 import React from 'react'
 import {
-  View,
+  AccessibilityProps,
+  StyleSheet,
   TextInput,
   TextInputProps,
   TextStyle,
+  View,
   ViewStyle,
-  StyleSheet,
-  AccessibilityProps,
 } from 'react-native'
 
+import {mergeRefs} from '#/lib/merge-refs'
 import {HITSLOP_20} from 'lib/constants'
-import {useTheme, atoms as a, web, android} from '#/alf'
-import {Text} from '#/components/Typography'
+import {android, atoms as a, useTheme, web} from '#/alf'
 import {useInteractionState} from '#/components/hooks/useInteractionState'
 import {Props as SVGIconProps} from '#/components/icons/common'
-import {mergeRefs} from '#/lib/merge-refs'
+import {Text} from '#/components/Typography'
 
 const Context = React.createContext<{
   inputRef: React.RefObject<TextInput> | null
diff --git a/src/components/moderation/GlobalModerationLabelPref.tsx b/src/components/moderation/GlobalModerationLabelPref.tsx
deleted file mode 100644
index 7633cb9f2..000000000
--- a/src/components/moderation/GlobalModerationLabelPref.tsx
+++ /dev/null
@@ -1,93 +0,0 @@
-import React from 'react'
-import {View} from 'react-native'
-import {InterpretedLabelValueDefinition, LabelPreference} from '@atproto/api'
-import {useLingui} from '@lingui/react'
-import {msg} from '@lingui/macro'
-
-import {useGlobalLabelStrings} from '#/lib/moderation/useGlobalLabelStrings'
-import {
-  usePreferencesQuery,
-  usePreferencesSetContentLabelMutation,
-} from '#/state/queries/preferences'
-
-import {useTheme, atoms as a} from '#/alf'
-import {Text} from '#/components/Typography'
-import * as ToggleButton from '#/components/forms/ToggleButton'
-
-export function GlobalModerationLabelPref({
-  labelValueDefinition,
-  disabled,
-}: {
-  labelValueDefinition: InterpretedLabelValueDefinition
-  disabled?: boolean
-}) {
-  const {_} = useLingui()
-  const t = useTheme()
-
-  const {identifier} = labelValueDefinition
-  const {data: preferences} = usePreferencesQuery()
-  const {mutate, variables} = usePreferencesSetContentLabelMutation()
-  const savedPref = preferences?.moderationPrefs.labels[identifier]
-  const pref = variables?.visibility ?? savedPref ?? 'warn'
-
-  const allLabelStrings = useGlobalLabelStrings()
-  const labelStrings =
-    labelValueDefinition.identifier in allLabelStrings
-      ? allLabelStrings[labelValueDefinition.identifier]
-      : {
-          name: labelValueDefinition.identifier,
-          description: `Labeled "${labelValueDefinition.identifier}"`,
-        }
-
-  const labelOptions = {
-    hide: _(msg`Hide`),
-    warn: _(msg`Warn`),
-    ignore: _(msg`Show`),
-  }
-
-  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, 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={[pref]}
-            onChange={newPref =>
-              mutate({
-                label: identifier,
-                visibility: newPref[0] as LabelPreference,
-                labelerDid: undefined,
-              })
-            }>
-            <ToggleButton.Button name="ignore" label={labelOptions.ignore}>
-              {labelOptions.ignore}
-            </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>
-    </View>
-  )
-}
diff --git a/src/components/moderation/LabelPreference.tsx b/src/components/moderation/LabelPreference.tsx
new file mode 100644
index 000000000..7d4bd9c32
--- /dev/null
+++ b/src/components/moderation/LabelPreference.tsx
@@ -0,0 +1,294 @@
+import React from 'react'
+import {View} from 'react-native'
+import {InterpretedLabelValueDefinition, LabelPreference} from '@atproto/api'
+import {useLingui} from '@lingui/react'
+import {msg, Trans} from '@lingui/macro'
+
+import {useGlobalLabelStrings} from '#/lib/moderation/useGlobalLabelStrings'
+import {
+  usePreferencesQuery,
+  usePreferencesSetContentLabelMutation,
+} from '#/state/queries/preferences'
+import {useLabelBehaviorDescription} from '#/lib/moderation/useLabelBehaviorDescription'
+import {getLabelStrings} from '#/lib/moderation/useLabelInfo'
+
+import {useTheme, atoms as a, useBreakpoints} from '#/alf'
+import {Text} from '#/components/Typography'
+import {InlineLink} from '#/components/Link'
+import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '../icons/CircleInfo'
+import * as ToggleButton from '#/components/forms/ToggleButton'
+
+export function Outer({children}: React.PropsWithChildren<{}>) {
+  return (
+    <View
+      style={[
+        a.flex_row,
+        a.gap_md,
+        a.px_lg,
+        a.py_lg,
+        a.justify_between,
+        a.flex_wrap,
+      ]}>
+      {children}
+    </View>
+  )
+}
+
+export function Content({
+  children,
+  name,
+  description,
+}: React.PropsWithChildren<{
+  name: string
+  description: string
+}>) {
+  const t = useTheme()
+  const {gtPhone} = useBreakpoints()
+
+  return (
+    <View style={[a.gap_xs, a.flex_1]}>
+      <Text style={[a.font_bold, gtPhone ? a.text_sm : a.text_md]}>{name}</Text>
+      <Text style={[t.atoms.text_contrast_medium, a.leading_snug]}>
+        {description}
+      </Text>
+
+      {children}
+    </View>
+  )
+}
+
+export function Buttons({
+  name,
+  values,
+  onChange,
+  ignoreLabel,
+  warnLabel,
+  hideLabel,
+}: {
+  name: string
+  values: ToggleButton.GroupProps['values']
+  onChange: ToggleButton.GroupProps['onChange']
+  ignoreLabel?: string
+  warnLabel?: string
+  hideLabel?: string
+}) {
+  const {_} = useLingui()
+  const {gtPhone} = useBreakpoints()
+
+  return (
+    <View style={[{minHeight: 35}, gtPhone ? undefined : a.w_full]}>
+      <ToggleButton.Group
+        label={_(
+          msg`Configure content filtering setting for category: ${name}`,
+        )}
+        values={values}
+        onChange={onChange}>
+        {ignoreLabel && (
+          <ToggleButton.Button name="ignore" label={ignoreLabel}>
+            {ignoreLabel}
+          </ToggleButton.Button>
+        )}
+        {warnLabel && (
+          <ToggleButton.Button name="warn" label={warnLabel}>
+            {warnLabel}
+          </ToggleButton.Button>
+        )}
+        {hideLabel && (
+          <ToggleButton.Button name="hide" label={hideLabel}>
+            {hideLabel}
+          </ToggleButton.Button>
+        )}
+      </ToggleButton.Group>
+    </View>
+  )
+}
+
+/**
+ * For use on the global Moderation screen to set prefs for a "global" label,
+ * not scoped to a single labeler.
+ */
+export function GlobalLabelPreference({
+  labelDefinition,
+  disabled,
+}: {
+  labelDefinition: InterpretedLabelValueDefinition
+  disabled?: boolean
+}) {
+  const {_} = useLingui()
+
+  const {identifier} = labelDefinition
+  const {data: preferences} = usePreferencesQuery()
+  const {mutate, variables} = usePreferencesSetContentLabelMutation()
+  const savedPref = preferences?.moderationPrefs.labels[identifier]
+  const pref = variables?.visibility ?? savedPref ?? 'warn'
+
+  const allLabelStrings = useGlobalLabelStrings()
+  const labelStrings =
+    labelDefinition.identifier in allLabelStrings
+      ? allLabelStrings[labelDefinition.identifier]
+      : {
+          name: labelDefinition.identifier,
+          description: `Labeled "${labelDefinition.identifier}"`,
+        }
+
+  const labelOptions = {
+    hide: _(msg`Hide`),
+    warn: _(msg`Warn`),
+    ignore: _(msg`Show`),
+  }
+
+  return (
+    <Outer>
+      <Content
+        name={labelStrings.name}
+        description={labelStrings.description}
+      />
+      {!disabled && (
+        <Buttons
+          name={labelStrings.name.toLowerCase()}
+          values={[pref]}
+          onChange={values => {
+            mutate({
+              label: identifier,
+              visibility: values[0] as LabelPreference,
+              labelerDid: undefined,
+            })
+          }}
+          ignoreLabel={labelOptions.ignore}
+          warnLabel={labelOptions.warn}
+          hideLabel={labelOptions.hide}
+        />
+      )}
+    </Outer>
+  )
+}
+
+/**
+ * For use on individual labeler pages
+ */
+export function LabelerLabelPreference({
+  labelDefinition,
+  disabled,
+  labelerDid,
+}: {
+  labelDefinition: InterpretedLabelValueDefinition
+  disabled?: boolean
+  labelerDid?: string
+}) {
+  const {i18n} = useLingui()
+  const t = useTheme()
+  const {gtPhone} = useBreakpoints()
+
+  const isGlobalLabel = !labelDefinition.definedBy
+  const {identifier} = labelDefinition
+  const {data: preferences} = usePreferencesQuery()
+  const {mutate, variables} = usePreferencesSetContentLabelMutation()
+  const savedPref =
+    labelerDid && !isGlobalLabel
+      ? preferences?.moderationPrefs.labelers.find(l => l.did === labelerDid)
+          ?.labels[identifier]
+      : preferences?.moderationPrefs.labels[identifier]
+  const pref =
+    variables?.visibility ??
+    savedPref ??
+    labelDefinition.defaultSetting ??
+    'warn'
+
+  // does the 'warn' setting make sense for this label?
+  const canWarn = !(
+    labelDefinition.blurs === 'none' && labelDefinition.severity === 'none'
+  )
+  // is this label adult only?
+  const adultOnly = labelDefinition.flags.includes('adult')
+  // is this label disabled because it's adult only?
+  const adultDisabled =
+    adultOnly && !preferences?.moderationPrefs.adultContentEnabled
+  // are there any reasons we cant configure this label here?
+  const cantConfigure = isGlobalLabel || adultDisabled
+  const showConfig = !disabled && (gtPhone || !cantConfigure)
+
+  // adjust the pref based on whether warn is available
+  let prefAdjusted = pref
+  if (adultDisabled) {
+    prefAdjusted = 'hide'
+  } else if (!canWarn && pref === 'warn') {
+    prefAdjusted = 'ignore'
+  }
+
+  // grab localized descriptions of the label and its settings
+  const currentPrefLabel = useLabelBehaviorDescription(
+    labelDefinition,
+    prefAdjusted,
+  )
+  const hideLabel = useLabelBehaviorDescription(labelDefinition, 'hide')
+  const warnLabel = useLabelBehaviorDescription(labelDefinition, 'warn')
+  const ignoreLabel = useLabelBehaviorDescription(labelDefinition, 'ignore')
+  const globalLabelStrings = useGlobalLabelStrings()
+  const labelStrings = getLabelStrings(
+    i18n.locale,
+    globalLabelStrings,
+    labelDefinition,
+  )
+
+  return (
+    <Outer>
+      <Content name={labelStrings.name} description={labelStrings.description}>
+        {cantConfigure && (
+          <View style={[a.flex_row, a.gap_xs, a.align_center, a.mt_xs]}>
+            <CircleInfo size="sm" fill={t.atoms.text_contrast_high.color} />
+
+            <Text
+              style={[t.atoms.text_contrast_medium, a.font_semibold, a.italic]}>
+              {adultDisabled ? (
+                <Trans>Adult content is disabled.</Trans>
+              ) : isGlobalLabel ? (
+                <Trans>
+                  Configured in{' '}
+                  <InlineLink to="/moderation" style={a.text_sm}>
+                    moderation settings
+                  </InlineLink>
+                  .
+                </Trans>
+              ) : null}
+            </Text>
+          </View>
+        )}
+      </Content>
+
+      {showConfig && (
+        <View style={[gtPhone ? undefined : a.w_full]}>
+          {cantConfigure ? (
+            <View
+              style={[
+                {minHeight: 35},
+                a.px_md,
+                a.py_md,
+                a.rounded_sm,
+                a.border,
+                t.atoms.border_contrast_low,
+              ]}>
+              <Text style={[a.font_bold, t.atoms.text_contrast_low]}>
+                {currentPrefLabel}
+              </Text>
+            </View>
+          ) : (
+            <Buttons
+              name={labelStrings.name.toLowerCase()}
+              values={[pref]}
+              onChange={values => {
+                mutate({
+                  label: identifier,
+                  visibility: values[0] as LabelPreference,
+                  labelerDid,
+                })
+              }}
+              ignoreLabel={ignoreLabel}
+              warnLabel={canWarn ? warnLabel : undefined}
+              hideLabel={hideLabel}
+            />
+          )}
+        </View>
+      )}
+    </Outer>
+  )
+}
diff --git a/src/components/moderation/ModerationLabelPref.tsx b/src/components/moderation/ModerationLabelPref.tsx
deleted file mode 100644
index b16c24859..000000000
--- a/src/components/moderation/ModerationLabelPref.tsx
+++ /dev/null
@@ -1,177 +0,0 @@
-import React from 'react'
-import {View} from 'react-native'
-import {InterpretedLabelValueDefinition, LabelPreference} from '@atproto/api'
-import {useLingui} from '@lingui/react'
-import {msg, Trans} from '@lingui/macro'
-
-import {useGlobalLabelStrings} from '#/lib/moderation/useGlobalLabelStrings'
-import {useLabelBehaviorDescription} from '#/lib/moderation/useLabelBehaviorDescription'
-import {
-  usePreferencesQuery,
-  usePreferencesSetContentLabelMutation,
-} from '#/state/queries/preferences'
-import {getLabelStrings} from '#/lib/moderation/useLabelInfo'
-
-import {useTheme, atoms as a, useBreakpoints} from '#/alf'
-import {Text} from '#/components/Typography'
-import {InlineLink} from '#/components/Link'
-import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '../icons/CircleInfo'
-import * as ToggleButton from '#/components/forms/ToggleButton'
-
-export function ModerationLabelPref({
-  labelValueDefinition,
-  labelerDid,
-  disabled,
-}: {
-  labelValueDefinition: InterpretedLabelValueDefinition
-  labelerDid: string | undefined
-  disabled?: boolean
-}) {
-  const {_, i18n} = useLingui()
-  const t = useTheme()
-  const {gtPhone} = useBreakpoints()
-
-  const isGlobalLabel = !labelValueDefinition.definedBy
-  const {identifier} = labelValueDefinition
-  const {data: preferences} = usePreferencesQuery()
-  const {mutate, variables} = usePreferencesSetContentLabelMutation()
-  const savedPref =
-    labelerDid && !isGlobalLabel
-      ? preferences?.moderationPrefs.labelers.find(l => l.did === labelerDid)
-          ?.labels[identifier]
-      : preferences?.moderationPrefs.labels[identifier]
-  const pref =
-    variables?.visibility ??
-    savedPref ??
-    labelValueDefinition.defaultSetting ??
-    'warn'
-
-  // does the 'warn' setting make sense for this label?
-  const canWarn = !(
-    labelValueDefinition.blurs === 'none' &&
-    labelValueDefinition.severity === 'none'
-  )
-  // is this label adult only?
-  const adultOnly = labelValueDefinition.flags.includes('adult')
-  // is this label disabled because it's adult only?
-  const adultDisabled =
-    adultOnly && !preferences?.moderationPrefs.adultContentEnabled
-  // are there any reasons we cant configure this label here?
-  const cantConfigure = isGlobalLabel || adultDisabled
-  const showConfig = !disabled && (gtPhone || !cantConfigure)
-
-  // adjust the pref based on whether warn is available
-  let prefAdjusted = pref
-  if (adultDisabled) {
-    prefAdjusted = 'hide'
-  } else if (!canWarn && pref === 'warn') {
-    prefAdjusted = 'ignore'
-  }
-
-  // grab localized descriptions of the label and its settings
-  const currentPrefLabel = useLabelBehaviorDescription(
-    labelValueDefinition,
-    prefAdjusted,
-  )
-  const hideLabel = useLabelBehaviorDescription(labelValueDefinition, 'hide')
-  const warnLabel = useLabelBehaviorDescription(labelValueDefinition, 'warn')
-  const ignoreLabel = useLabelBehaviorDescription(
-    labelValueDefinition,
-    'ignore',
-  )
-  const globalLabelStrings = useGlobalLabelStrings()
-  const labelStrings = getLabelStrings(
-    i18n.locale,
-    globalLabelStrings,
-    labelValueDefinition,
-  )
-
-  return (
-    <View
-      style={[
-        a.flex_row,
-        a.gap_md,
-        a.px_lg,
-        a.py_lg,
-        a.justify_between,
-        a.flex_wrap,
-      ]}>
-      <View style={[a.gap_xs, a.flex_1]}>
-        <Text style={[a.font_bold, gtPhone ? a.text_sm : a.text_md]}>
-          {labelStrings.name}
-        </Text>
-        <Text style={[t.atoms.text_contrast_medium, a.leading_snug]}>
-          {labelStrings.description}
-        </Text>
-
-        {cantConfigure && (
-          <View style={[a.flex_row, a.gap_xs, a.align_center, a.mt_xs]}>
-            <CircleInfo size="sm" fill={t.atoms.text_contrast_high.color} />
-
-            <Text
-              style={[t.atoms.text_contrast_medium, a.font_semibold, a.italic]}>
-              {adultDisabled ? (
-                <Trans>Adult content is disabled.</Trans>
-              ) : isGlobalLabel ? (
-                <Trans>
-                  Configured in{' '}
-                  <InlineLink to="/moderation" style={a.text_sm}>
-                    moderation settings
-                  </InlineLink>
-                  .
-                </Trans>
-              ) : null}
-            </Text>
-          </View>
-        )}
-      </View>
-
-      {showConfig && (
-        <View style={[gtPhone ? undefined : a.w_full]}>
-          {cantConfigure ? (
-            <View
-              style={[
-                {minHeight: 35},
-                a.px_md,
-                a.py_md,
-                a.rounded_sm,
-                a.border,
-                t.atoms.border_contrast_low,
-              ]}>
-              <Text style={[a.font_bold, t.atoms.text_contrast_low]}>
-                {currentPrefLabel}
-              </Text>
-            </View>
-          ) : (
-            <View style={[{minHeight: 35}]}>
-              <ToggleButton.Group
-                label={_(
-                  msg`Configure content filtering setting for category: ${labelStrings.name.toLowerCase()}`,
-                )}
-                values={[prefAdjusted]}
-                onChange={newPref =>
-                  mutate({
-                    label: identifier,
-                    visibility: newPref[0] as LabelPreference,
-                    labelerDid,
-                  })
-                }>
-                <ToggleButton.Button name="ignore" label={ignoreLabel}>
-                  {ignoreLabel}
-                </ToggleButton.Button>
-                {canWarn && (
-                  <ToggleButton.Button name="warn" label={warnLabel}>
-                    {warnLabel}
-                  </ToggleButton.Button>
-                )}
-                <ToggleButton.Button name="hide" label={hideLabel}>
-                  {hideLabel}
-                </ToggleButton.Button>
-              </ToggleButton.Group>
-            </View>
-          )}
-        </View>
-      )}
-    </View>
-  )
-}
diff --git a/src/screens/Moderation/index.tsx b/src/screens/Moderation/index.tsx
index d73823fad..7d991cc71 100644
--- a/src/screens/Moderation/index.tsx
+++ b/src/screens/Moderation/index.tsx
@@ -41,7 +41,7 @@ import {InlineLink, Link} from '#/components/Link'
 import {Button, ButtonText} from '#/components/Button'
 import {Loader} from '#/components/Loader'
 import * as LabelingService from '#/components/LabelingServiceCard'
-import {GlobalModerationLabelPref} from '#/components/moderation/GlobalModerationLabelPref'
+import {GlobalLabelPreference} from '#/components/moderation/LabelPreference'
 import {useGlobalDialogsControlContext} from '#/components/dialogs/Context'
 import {Props as SVGIconProps} from '#/components/icons/common'
 import {BirthDateSettingsDialog} from '#/components/dialogs/BirthDateSettings'
@@ -352,17 +352,17 @@ export function ModerationScreenInner({
           )}
           {!isUnderage && adultContentEnabled && (
             <>
-              <GlobalModerationLabelPref labelValueDefinition={LABELS.porn} />
+              <GlobalLabelPreference labelDefinition={LABELS.porn} />
               <Divider />
-              <GlobalModerationLabelPref labelValueDefinition={LABELS.sexual} />
+              <GlobalLabelPreference labelDefinition={LABELS.sexual} />
               <Divider />
-              <GlobalModerationLabelPref
-                labelValueDefinition={LABELS['graphic-media']}
+              <GlobalLabelPreference
+                labelDefinition={LABELS['graphic-media']}
               />
               <Divider />
             </>
           )}
-          <GlobalModerationLabelPref labelValueDefinition={LABELS.nudity} />
+          <GlobalLabelPreference labelDefinition={LABELS.nudity} />
         </View>
       </View>
 
diff --git a/src/screens/Profile/Sections/Labels.tsx b/src/screens/Profile/Sections/Labels.tsx
index 08db4a861..2b2b99594 100644
--- a/src/screens/Profile/Sections/Labels.tsx
+++ b/src/screens/Profile/Sections/Labels.tsx
@@ -23,7 +23,7 @@ import {Loader} from '#/components/Loader'
 import {Divider} from '#/components/Divider'
 import {CenteredView, ScrollView} from '#/view/com/util/Views'
 import {ErrorState} from '../ErrorState'
-import {ModerationLabelPref} from '#/components/moderation/ModerationLabelPref'
+import {LabelerLabelPreference} from '#/components/moderation/LabelPreference'
 import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
 
 interface LabelsSectionProps {
@@ -197,9 +197,9 @@ export function ProfileLabelsSectionInner({
               return (
                 <React.Fragment key={labelDef.identifier}>
                   {i !== 0 && <Divider />}
-                  <ModerationLabelPref
+                  <LabelerLabelPreference
                     disabled={isSubscribed ? undefined : true}
-                    labelValueDefinition={labelDef}
+                    labelDefinition={labelDef}
                     labelerDid={labelerInfo.creator.did}
                   />
                 </React.Fragment>
diff --git a/src/view/com/auth/SplashScreen.tsx b/src/view/com/auth/SplashScreen.tsx
index fe0d4ee49..5e431742e 100644
--- a/src/view/com/auth/SplashScreen.tsx
+++ b/src/view/com/auth/SplashScreen.tsx
@@ -1,21 +1,21 @@
 import React from 'react'
 import {View} from 'react-native'
+import RNPickerSelect, {PickerSelectProps} from 'react-native-picker-select'
 import {useSafeAreaInsets} from 'react-native-safe-area-context'
-
-import {ErrorBoundary} from 'view/com/util/ErrorBoundary'
-import {CenteredView} from '../util/Views'
-import {Trans, msg} from '@lingui/macro'
+import {msg, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
-import {Logo} from '#/view/icons/Logo'
-import {Logotype} from '#/view/icons/Logotype'
-import RNPickerSelect, {PickerSelectProps} from 'react-native-picker-select'
+
 import {sanitizeAppLanguageSetting} from '#/locale/helpers'
-import {useLanguagePrefs, useLanguagePrefsApi} from '#/state/preferences'
 import {APP_LANGUAGES} from '#/locale/languages'
+import {useLanguagePrefs, useLanguagePrefsApi} from '#/state/preferences'
+import {Logo} from '#/view/icons/Logo'
+import {Logotype} from '#/view/icons/Logotype'
+import {ErrorBoundary} from 'view/com/util/ErrorBoundary'
 import {atoms as a, useTheme} from '#/alf'
-import {Text} from '#/components/Typography'
 import {Button, ButtonText} from '#/components/Button'
 import {ChevronBottom_Stroke2_Corner0_Rounded as ChevronDown} from '#/components/icons/Chevron'
+import {Text} from '#/components/Typography'
+import {CenteredView} from '../util/Views'
 
 export const SplashScreen = ({
   onPressSignin,
diff --git a/src/view/com/auth/SplashScreen.web.tsx b/src/view/com/auth/SplashScreen.web.tsx
index e8f312491..5361baa76 100644
--- a/src/view/com/auth/SplashScreen.web.tsx
+++ b/src/view/com/auth/SplashScreen.web.tsx
@@ -1,21 +1,22 @@
 import React from 'react'
-import {View, Pressable} from 'react-native'
+import {Pressable, View} from 'react-native'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
-import {ErrorBoundary} from 'view/com/util/ErrorBoundary'
-import {CenteredView} from '../util/Views'
-import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
-import {Trans, msg} from '@lingui/macro'
-import {Logo} from '#/view/icons/Logo'
-import {Logotype} from '#/view/icons/Logotype'
+import {msg, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
+
 import {sanitizeAppLanguageSetting} from '#/locale/helpers'
-import {useLanguagePrefs, useLanguagePrefsApi} from '#/state/preferences'
 import {APP_LANGUAGES} from '#/locale/languages'
+import {useLanguagePrefs, useLanguagePrefsApi} from '#/state/preferences'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
+import {Logo} from '#/view/icons/Logo'
+import {Logotype} from '#/view/icons/Logotype'
+import {ErrorBoundary} from 'view/com/util/ErrorBoundary'
 import {atoms as a, useTheme} from '#/alf'
 import {Button, ButtonText} from '#/components/Button'
 import {ChevronBottom_Stroke2_Corner0_Rounded as ChevronDown} from '#/components/icons/Chevron'
-import {Text} from '#/components/Typography'
 import {InlineLink} from '#/components/Link'
+import {Text} from '#/components/Typography'
+import {CenteredView} from '../util/Views'
 
 export const SplashScreen = ({
   onDismiss,
diff --git a/src/view/com/post-thread/PostThread.tsx b/src/view/com/post-thread/PostThread.tsx
index cf52e8fa4..c1159379d 100644
--- a/src/view/com/post-thread/PostThread.tsx
+++ b/src/view/com/post-thread/PostThread.tsx
@@ -1,36 +1,36 @@
 import React, {useEffect, useRef} from 'react'
 import {StyleSheet, useWindowDimensions, View} from 'react-native'
 import {AppBskyFeedDefs} from '@atproto/api'
-import {Trans, msg} from '@lingui/macro'
+import {msg, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 
-import {List, ListMethods} from '../util/List'
-import {PostThreadItem} from './PostThreadItem'
-import {ComposePrompt} from '../composer/Prompt'
-import {ViewHeader} from '../util/ViewHeader'
-import {Text} from '../util/text/Text'
-import {usePalette} from 'lib/hooks/usePalette'
-import {useSetTitle} from 'lib/hooks/useSetTitle'
+import {moderatePost_wrapped as moderatePost} from '#/lib/moderatePost_wrapped'
+import {isAndroid, isNative, isWeb} from '#/platform/detection'
 import {
+  sortThread,
+  ThreadBlocked,
   ThreadNode,
-  ThreadPost,
   ThreadNotFound,
-  ThreadBlocked,
+  ThreadPost,
   usePostThreadQuery,
-  sortThread,
 } from '#/state/queries/post-thread'
-import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
-import {sanitizeDisplayName} from 'lib/strings/display-names'
 import {
   useModerationOpts,
   usePreferencesQuery,
 } from '#/state/queries/preferences'
 import {useSession} from '#/state/session'
-import {isAndroid, isNative, isWeb} from '#/platform/detection'
-import {moderatePost_wrapped as moderatePost} from '#/lib/moderatePost_wrapped'
 import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender'
-import {ListFooter, ListMaybePlaceholder} from '#/components/Lists'
+import {usePalette} from 'lib/hooks/usePalette'
+import {useSetTitle} from 'lib/hooks/useSetTitle'
+import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
+import {sanitizeDisplayName} from 'lib/strings/display-names'
 import {cleanError} from 'lib/strings/errors'
+import {ListFooter, ListMaybePlaceholder} from '#/components/Lists'
+import {ComposePrompt} from '../composer/Prompt'
+import {List, ListMethods} from '../util/List'
+import {Text} from '../util/text/Text'
+import {ViewHeader} from '../util/ViewHeader'
+import {PostThreadItem} from './PostThreadItem'
 
 // FlatList maintainVisibleContentPosition breaks if too many items
 // are prepended. This seems to be an optimal number based on *shrug*.