Mods UI fixes (#3296)

* Fix report dialog buttons on Android by adjusting styles

* Dry up label pref comp
zio/stable
Eric Bailey 2024-03-21 12:21:36 -05:00 committed by GitHub
parent 4ff2bb7aba
commit 5f39ca3187
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 390 additions and 380 deletions

View File

@ -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

View File

@ -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>
)

View File

@ -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" />

View File

@ -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

View File

@ -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>
)
}

View File

@ -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>
)
}

View File

@ -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>
)
}

View File

@ -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>

View File

@ -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>

View File

@ -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 {sanitizeAppLanguageSetting} from '#/locale/helpers'
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 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 {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,

View File

@ -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 {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {sanitizeAppLanguageSetting} from '#/locale/helpers'
import {APP_LANGUAGES} from '#/locale/languages'
import {useLanguagePrefs, useLanguagePrefsApi} from '#/state/preferences'
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 {useLingui} from '@lingui/react'
import {sanitizeAppLanguageSetting} from '#/locale/helpers'
import {useLanguagePrefs, useLanguagePrefsApi} from '#/state/preferences'
import {APP_LANGUAGES} from '#/locale/languages'
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,

View File

@ -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 {
ThreadNode,
ThreadPost,
ThreadNotFound,
ThreadBlocked,
usePostThreadQuery,
sortThread,
ThreadBlocked,
ThreadNode,
ThreadNotFound,
ThreadPost,
usePostThreadQuery,
} 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*.