Implement preference controls on labelers
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user