diff --git a/src/components/Pills.tsx b/src/components/Pills.tsx index 2fff999373..d48089f883 100644 --- a/src/components/Pills.tsx +++ b/src/components/Pills.tsx @@ -13,6 +13,15 @@ import { } from '#/components/moderation/ModerationDetailsDialog' import {Text} from '#/components/Typography' +export type AppModerationCause = + | ModerationCause + | { + type: 'reply-hidden' + source: {type: 'user'} + priority: 6 + downgraded?: boolean + } + export type CommonProps = { size?: 'sm' | 'lg' } @@ -40,7 +49,7 @@ export function Row({ } export type LabelProps = { - cause: ModerationCause + cause: AppModerationCause disableDetailsDialog?: boolean noBg?: boolean } & CommonProps diff --git a/src/components/moderation/ModerationDetailsDialog.tsx b/src/components/moderation/ModerationDetailsDialog.tsx index ebfe452325..0073e64aa4 100644 --- a/src/components/moderation/ModerationDetailsDialog.tsx +++ b/src/components/moderation/ModerationDetailsDialog.tsx @@ -12,13 +12,14 @@ import {atoms as a, useTheme} from '#/alf' import * as Dialog from '#/components/Dialog' import {Divider} from '#/components/Divider' import {InlineLinkText} from '#/components/Link' +import {AppModerationCause} from '#/components/Pills' import {Text} from '#/components/Typography' export {useDialogControl as useModerationDetailsDialogControl} from '#/components/Dialog' export interface ModerationDetailsDialogProps { control: Dialog.DialogOuterProps['control'] - modcause: ModerationCause + modcause: ModerationCause | AppModerationCause } export function ModerationDetailsDialog(props: ModerationDetailsDialogProps) { @@ -105,6 +106,9 @@ function ModerationDetailsDialogInner({ } else if (modcause.type === 'hidden') { name = _(msg`Post Hidden by You`) description = _(msg`You have hidden this post.`) + } else if (modcause.type === 'reply-hidden') { + name = _(msg`Post Hidden by Thread Author`) + description = _(msg`The author of this thread has hidden this post.`) } else if (modcause.type === 'label') { name = desc.name description = desc.description diff --git a/src/components/moderation/PostAlerts.tsx b/src/components/moderation/PostAlerts.tsx index efbf182193..6c4e5f8c82 100644 --- a/src/components/moderation/PostAlerts.tsx +++ b/src/components/moderation/PostAlerts.tsx @@ -1,6 +1,6 @@ import React from 'react' import {StyleProp, ViewStyle} from 'react-native' -import {ModerationUI} from '@atproto/api' +import {ModerationCause, ModerationUI} from '@atproto/api' import {getModerationCauseKey} from '#/lib/moderation' import * as Pills from '#/components/Pills' @@ -9,13 +9,15 @@ export function PostAlerts({ modui, size = 'sm', style, + additionalCauses, }: { modui: ModerationUI size?: Pills.CommonProps['size'] includeMute?: boolean style?: StyleProp + additionalCauses?: ModerationCause[] | Pills.AppModerationCause[] }) { - if (!modui.alert && !modui.inform) { + if (!modui.alert && !modui.inform && !additionalCauses?.length) { return null } @@ -37,6 +39,14 @@ export function PostAlerts({ noBg={size === 'sm'} /> ))} + {additionalCauses?.map(cause => ( + + ))} ) } diff --git a/src/lib/moderation.ts b/src/lib/moderation.ts index 4105c2c2dd..3c96deecba 100644 --- a/src/lib/moderation.ts +++ b/src/lib/moderation.ts @@ -1,17 +1,20 @@ import { - ModerationCause, - ModerationUI, - InterpretedLabelValueDefinition, - LABELS, AppBskyLabelerDefs, BskyAgent, + InterpretedLabelValueDefinition, + LABELS, + ModerationCause, ModerationOpts, + ModerationUI, } from '@atproto/api' import {sanitizeDisplayName} from '#/lib/strings/display-names' import {sanitizeHandle} from '#/lib/strings/handles' +import {AppModerationCause} from '#/components/Pills' -export function getModerationCauseKey(cause: ModerationCause): string { +export function getModerationCauseKey( + cause: ModerationCause | AppModerationCause, +): string { const source = cause.source.type === 'labeler' ? cause.source.did diff --git a/src/lib/moderation/useModerationCauseDescription.ts b/src/lib/moderation/useModerationCauseDescription.ts index be9014029c..e2d5ae5e70 100644 --- a/src/lib/moderation/useModerationCauseDescription.ts +++ b/src/lib/moderation/useModerationCauseDescription.ts @@ -13,6 +13,7 @@ import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/ico import {Props as SVGIconProps} from '#/components/icons/common' import {EyeSlash_Stroke2_Corner0_Rounded as EyeSlash} from '#/components/icons/EyeSlash' import {Warning_Stroke2_Corner0_Rounded as Warning} from '#/components/icons/Warning' +import {AppModerationCause} from '#/components/Pills' import {useGlobalLabelStrings} from './useGlobalLabelStrings' import {getDefinition, getLabelStrings} from './useLabelInfo' @@ -27,7 +28,7 @@ export interface ModerationCauseDescription { } export function useModerationCauseDescription( - cause: ModerationCause | undefined, + cause: ModerationCause | AppModerationCause | undefined, ): ModerationCauseDescription { const {_, i18n} = useLingui() const {labelDefs, labelers} = useLabelDefinitions() @@ -111,6 +112,13 @@ export function useModerationCauseDescription( description: _(msg`You have hidden this post`), } } + if (cause.type === 'reply-hidden') { + return { + icon: EyeSlash, + name: _(msg`Post Hidden by Thread Author`), + description: _(msg`The author of this thread has hidden this post.`), + } + } if (cause.type === 'label') { const def = cause.labelDef || getDefinition(labelDefs, cause.label) const strings = getLabelStrings(i18n.locale, globalLabelStrings, def) diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx index 47bdf185e3..fc14290070 100644 --- a/src/view/com/post-thread/PostThreadItem.tsx +++ b/src/view/com/post-thread/PostThreadItem.tsx @@ -15,6 +15,7 @@ import {POST_TOMBSTONE, Shadow, usePostShadow} from '#/state/cache/post-shadow' import {useLanguagePrefs} from '#/state/preferences' import {useOpenLink} from '#/state/preferences/in-app-browser' import {ThreadPost} from '#/state/queries/post-thread' +import {useThreadgateRecordQuery} from '#/state/queries/threadgate' import {useComposerControls} from '#/state/shell/composer' import {MAX_POST_LINES} from 'lib/constants' import {usePalette} from 'lib/hooks/usePalette' @@ -29,6 +30,7 @@ import {isWeb} from 'platform/detection' import {useSession} from 'state/session' import {PostThreadFollowBtn} from 'view/com/post-thread/PostThreadFollowBtn' import {atoms as a} from '#/alf' +import {AppModerationCause} from '#/components/Pills' import {RichText} from '#/components/RichText' import {ContentHider} from '../../../components/moderation/ContentHider' import {LabelsOnMyPost} from '../../../components/moderation/LabelsOnMe' @@ -199,6 +201,21 @@ let PostThreadItemLoaded = ({ return makeProfileLink(post.author, 'post', urip.rkey, 'reposted-by') }, [post.uri, post.author]) const repostsTitle = _(msg`Reposts of this post`) + const {data: threadgateRecord} = useThreadgateRecordQuery({ + postUri: rootUri, + }) + const isPostHiddenByThreadgate = threadgateRecord?.hiddenReplies?.includes( + post.uri, + ) + const additionalPostAlerts: AppModerationCause[] = isPostHiddenByThreadgate + ? [ + { + type: 'reply-hidden', + source: {type: 'user'}, + priority: 6, + }, + ] + : [] const translatorUrl = getTranslatorLink( record?.text || '', @@ -315,6 +332,7 @@ let PostThreadItemLoaded = ({ size="lg" includeMute style={[a.pt_2xs, a.pb_sm]} + additionalCauses={additionalPostAlerts} /> {richText?.text ? ( {richText?.text ? (