import React from 'react' import {Keyboard, Platform, StyleProp, View, ViewStyle} from 'react-native' import { AppBskyFeedDefs, AppBskyFeedPost, AppBskyGraphDefs, AtUri, } from '@atproto/api' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {HITSLOP_10} from '#/lib/constants' import {makeListLink, makeProfileLink} from '#/lib/routes/links' import {isNative} from '#/platform/detection' import { ThreadgateAllowUISetting, threadgateViewToAllowUISetting, } from '#/state/queries/threadgate' import {atoms as a, useTheme} from '#/alf' import {Button} from '#/components/Button' import * as Dialog from '#/components/Dialog' import {useDialogControl} from '#/components/Dialog' import { PostInteractionSettingsDialog, usePrefetchPostInteractionSettings, } from '#/components/dialogs/PostInteractionSettingsDialog' import {CircleBanSign_Stroke2_Corner0_Rounded as CircleBanSign} from '#/components/icons/CircleBanSign' import {Earth_Stroke2_Corner0_Rounded as Earth} from '#/components/icons/Globe' import {Group3_Stroke2_Corner0_Rounded as Group} from '#/components/icons/Group' import {InlineLinkText} from '#/components/Link' import {Text} from '#/components/Typography' import {PencilLine_Stroke2_Corner0_Rounded as PencilLine} from './icons/Pencil' interface WhoCanReplyProps { post: AppBskyFeedDefs.PostView isThreadAuthor: boolean style?: StyleProp } export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) { const {_} = useLingui() const t = useTheme() const infoDialogControl = useDialogControl() const editDialogControl = useDialogControl() /* * `WhoCanReply` is only used for root posts atm, in case this changes * unexpectedly, we should check to make sure it's for sure the root URI. */ const rootUri = AppBskyFeedPost.isRecord(post.record) && post.record.reply?.root ? post.record.reply.root.uri : post.uri const settings = React.useMemo(() => { return threadgateViewToAllowUISetting(post.threadgate) }, [post.threadgate]) const prefetchPostInteractionSettings = usePrefetchPostInteractionSettings({ postUri: post.uri, rootPostUri: rootUri, }) const anyoneCanReply = settings.length === 1 && settings[0].type === 'everybody' const noOneCanReply = settings.length === 1 && settings[0].type === 'nobody' const description = anyoneCanReply ? _(msg`Everybody can reply`) : noOneCanReply ? _(msg`Replies disabled`) : _(msg`Some people can reply`) const onPressOpen = () => { if (isNative && Keyboard.isVisible()) { Keyboard.dismiss() } if (isThreadAuthor) { editDialogControl.open() } else { infoDialogControl.open() } } return ( <> {isThreadAuthor ? ( ) : ( )} ) } function Icon({ color, width, settings, }: { color: string width?: number settings: ThreadgateAllowUISetting[] }) { const isEverybody = settings.length === 0 const isNobody = !!settings.find(gate => gate.type === 'nobody') const IconComponent = isEverybody ? Earth : isNobody ? CircleBanSign : Group return } function WhoCanReplyDialog({ control, post, settings, embeddingDisabled, }: { control: Dialog.DialogControlProps post: AppBskyFeedDefs.PostView settings: ThreadgateAllowUISetting[] embeddingDisabled: boolean }) { const {_} = useLingui() return ( Who can interact with this post? ) } function Rules({ post, settings, embeddingDisabled, }: { post: AppBskyFeedDefs.PostView settings: ThreadgateAllowUISetting[] embeddingDisabled: boolean }) { const t = useTheme() return ( <> {settings.length === 0 ? ( This post has an unknown type of threadgate on it. Your app may be out of date. ) : settings[0].type === 'everybody' ? ( Everybody can reply to this post. ) : settings[0].type === 'nobody' ? ( Replies to this post are disabled. ) : ( Only{' '} {settings.map((rule, i) => ( ))}{' '} can reply. )}{' '} {embeddingDisabled && ( No one but the author can quote this post. )} ) } function Rule({ rule, post, lists, }: { rule: ThreadgateAllowUISetting post: AppBskyFeedDefs.PostView lists: AppBskyGraphDefs.ListViewBasic[] | undefined }) { if (rule.type === 'mention') { return mentioned users } if (rule.type === 'followers') { return ( users following{' '} @{post.author.handle} ) } if (rule.type === 'following') { return ( users followed by{' '} @{post.author.handle} ) } if (rule.type === 'list') { const list = lists?.find(l => l.uri === rule.list) if (list) { const listUrip = new AtUri(list.uri) return ( {list.name} {' '} members ) } } } function Separator({i, length}: {i: number; length: number}) { if (length < 2 || i === length - 1) { return null } if (i === length - 2) { return ( <> {length > 2 ? ',' : ''} and{' '} ) } return <>, }