Implement preference controls on labelers

This commit is contained in:
Paul Frazee
2024-03-04 18:14:02 -08:00
parent b26e280373
commit 19c0ae80eb
8 changed files with 440 additions and 97 deletions
@@ -137,7 +137,7 @@ let ProfileHeaderLabeler = ({
isPlaceholderProfile={isPlaceholderProfile}>
<View style={[a.px_lg, a.pt_md, a.pb_sm]} pointerEvents="box-none">
<View
style={[a.flex_row, a.justify_end, a.gap_sm, a.pb_sm]}
style={[a.flex_row, a.justify_end, a.gap_sm, a.pb_lg]}
pointerEvents="box-none">
{isMe ? (
<Button
+123 -60
View File
@@ -10,9 +10,13 @@ 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 {useScrollHandlers} from '#/lib/ScrollContext'
import {runOnJS} from 'react-native-reanimated'
import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
import {lookupLabelValueDefinition} from '#/lib/moderation'
import {ListRef} from '#/view/com/util/List'
import {SectionRef} from './types'
import {isNative} from '#/platform/detection'
import {useTheme, atoms as a} from '#/alf'
import {Text} from '#/components/Typography'
@@ -23,20 +27,44 @@ import {CenteredView, ScrollView} from '#/view/com/util/Views'
import {ErrorState} from '../ErrorState'
import {ModerationLabelPref} from '#/components/ModerationLabelPref'
export function ProfileLabelsSection({
isLabelerLoading,
labelerInfo,
labelerError,
moderationOpts,
}: {
interface LabelsSectionProps {
isLabelerLoading: boolean
labelerInfo: AppBskyLabelerDefs.LabelerViewDetailed | undefined
labelerError: Error | null
moderationOpts: ModerationOpts
}) {
scrollElRef: ListRef
headerHeight: number
}
export const ProfileLabelsSection = React.forwardRef<
SectionRef,
LabelsSectionProps
>(function LabelsSectionImpl(
{
isLabelerLoading,
labelerInfo,
labelerError,
moderationOpts,
scrollElRef,
headerHeight,
},
ref,
) {
const t = useTheme()
const {_} = useLingui()
const {height: minHeight} = useSafeAreaFrame()
const onScrollToTop = React.useCallback(() => {
scrollElRef.current?.scrollTo({
animated: isNative,
x: 0,
y: -headerHeight,
})
}, [scrollElRef, headerHeight])
React.useImperativeHandle(ref, () => ({
scrollToTop: onScrollToTop,
}))
return (
<CenteredView>
<View
@@ -64,22 +92,42 @@ export function ProfileLabelsSection({
<ProfileLabelsSectionInner
moderationOpts={moderationOpts}
labelerInfo={labelerInfo}
scrollElRef={scrollElRef}
headerHeight={headerHeight}
/>
)}
</View>
</CenteredView>
)
}
})
export function ProfileLabelsSectionInner({
moderationOpts,
labelerInfo,
scrollElRef,
headerHeight,
}: {
moderationOpts: ModerationOpts
labelerInfo: AppBskyLabelerDefs.LabelerViewDetailed
scrollElRef: ListRef
headerHeight: number
}) {
const {_} = useLingui()
const t = useTheme()
const contextScrollHandlers = useScrollHandlers()
const scrollHandler = useAnimatedScrollHandler({
onBeginDrag(e, ctx) {
contextScrollHandlers.onBeginDrag?.(e, ctx)
},
onEndDrag(e, ctx) {
contextScrollHandlers.onEndDrag?.(e, ctx)
},
onScroll(e, ctx) {
contextScrollHandlers.onScroll?.(e, ctx)
},
})
const {labelValues} = labelerInfo.policies
const isSubscribed = moderationOpts.prefs.mods.find(
mod => mod.did === labelerInfo.creator.did,
@@ -93,66 +141,81 @@ export function ProfileLabelsSectionInner({
) as InterprettedLabelValueDefinition[]
}, [labelerInfo, labelValues])
console.log(headerHeight, scrollElRef.current)
return (
<ScrollView
ref={scrollElRef}
scrollEventThrottle={1}
contentContainerStyle={{
paddingTop: headerHeight,
borderWidth: 0,
paddingHorizontal: a.px_xl.paddingLeft,
}}>
<View style={[a.pt_xl]}>
<Text style={[t.atoms.text_contrast_high, a.leading_snug, a.text_sm]}>
<Trans>
Labels are annotations on users and content. They can be used to
hide, warn, and categorize the network.
</Trans>
</Text>
{labelValues.length === 0 ? (
<Text
style={[
a.pt_xl,
t.atoms.text_contrast_high,
a.leading_snug,
a.text_sm,
]}>
}}
contentOffset={{x: 0, y: headerHeight * -1}}
onScroll={scrollHandler}>
<View
style={[
a.pt_xl,
a.px_xl,
isNative && a.border_t,
t.atoms.border_contrast_low,
]}>
<View>
<Text style={[t.atoms.text_contrast_high, a.leading_snug, a.text_sm]}>
<Trans>
This labeler hasn't declared what labels it publishes, and may not
be active.
Labels are annotations on users and content. They can be used to
hide, warn, and categorize the network.
</Trans>
</Text>
) : !isSubscribed ? (
<Text
style={[
a.pt_xl,
t.atoms.text_contrast_high,
a.leading_snug,
a.text_sm,
]}>
<Trans>
Subscribe to @{labelerInfo.creator.handle} to use these labels:
</Trans>
</Text>
) : null}
</View>
{labelDefs.length > 0 && (
<View style={[a.mt_xl, t.atoms.bg_contrast_25, a.rounded_md, a.py_xs]}>
{labelDefs.map((labelDef, i) => {
return (
<React.Fragment key={labelDef.identifier}>
{i !== 0 && <Divider />}
<View style={[a.py_md, a.px_md]}>
<ModerationLabelPref
disabled={isSubscribed ? undefined : true}
labelValueDefinition={labelDef}
/>
</View>
</React.Fragment>
)
})}
{labelValues.length === 0 ? (
<Text
style={[
a.pt_xl,
t.atoms.text_contrast_high,
a.leading_snug,
a.text_sm,
]}>
<Trans>
This labeler hasn't declared what labels it publishes, and may
not be active.
</Trans>
</Text>
) : !isSubscribed ? (
<Text
style={[
a.pt_xl,
t.atoms.text_contrast_high,
a.leading_snug,
a.text_sm,
]}>
<Trans>
Subscribe to @{labelerInfo.creator.handle} to use these labels:
</Trans>
</Text>
) : null}
</View>
)}
{labelDefs.length > 0 && (
<View
style={[a.mt_xl, t.atoms.bg_contrast_25, a.rounded_md, a.py_xs]}>
{labelDefs.map((labelDef, i) => {
return (
<React.Fragment key={labelDef.identifier}>
{i !== 0 && <Divider />}
<View style={[a.py_md, a.px_md]}>
<ModerationLabelPref
disabled={isSubscribed ? undefined : true}
labelValueDefinition={labelDef}
labelerDid={labelerInfo.creator.did}
/>
</View>
</React.Fragment>
)
})}
</View>
)}
<View style={{height: 100}} />
<View style={{height: 400}} />
</View>
</ScrollView>
)
}