[Chat] Add message item blocked state (#10616)

This commit is contained in:
Samuel Newman
2026-05-26 20:22:18 +03:00
committed by GitHub
parent 8720ef72ce
commit 5bad7d3ceb
+111 -2
View File
@@ -26,18 +26,25 @@ import {plural} from '@lingui/core/macro'
import {Trans, useLingui} from '@lingui/react/macro' import {Trans, useLingui} from '@lingui/react/macro'
import {useQueryClient} from '@tanstack/react-query' import {useQueryClient} from '@tanstack/react-query'
import {isBlockedOrBlocking} from '#/lib/moderation/blocked-and-muted'
import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name' import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name'
import {makeProfileLink} from '#/lib/routes/links' import {makeProfileLink} from '#/lib/routes/links'
import {sanitizeHandle} from '#/lib/strings/handles'
import {useMaybeProfileShadow} from '#/state/cache/profile-shadow'
import {type Shadow} from '#/state/cache/types'
import {type ConvoItem} from '#/state/messages/convo/types' import {type ConvoItem} from '#/state/messages/convo/types'
import {useModerationOpts} from '#/state/preferences/moderation-opts' import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {useProfileBlockMutationQueue} from '#/state/queries/profile'
import {unstableCacheProfileView} from '#/state/queries/unstable-profile-cache' import {unstableCacheProfileView} from '#/state/queries/unstable-profile-cache'
import {useSession} from '#/state/session' import {useSession} from '#/state/session'
import {atoms as a, native, platform, useTheme} from '#/alf' import {atoms as a, native, platform, useTheme} from '#/alf'
import {isOnlyEmoji} from '#/alf/typography' import {isOnlyEmoji} from '#/alf/typography'
import {Button} from '#/components/Button'
import {useDialogControl} from '#/components/Dialog' import {useDialogControl} from '#/components/Dialog'
import {ActionsWrapper} from '#/components/dms/ActionsWrapper' import {ActionsWrapper} from '#/components/dms/ActionsWrapper'
import {InlineLinkText, Link} from '#/components/Link' import {InlineLinkText, Link} from '#/components/Link'
import * as ProfileCard from '#/components/ProfileCard' import * as ProfileCard from '#/components/ProfileCard'
import * as Prompt from '#/components/Prompt'
import {RichText} from '#/components/RichText' import {RichText} from '#/components/RichText'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
import {DateDivider} from './DateDivider' import {DateDivider} from './DateDivider'
@@ -109,7 +116,7 @@ let MessageItem = ({
const queryClient = useQueryClient() const queryClient = useQueryClient()
const {message} = item const {message} = item
const profile = relatedProfiles.get(message.sender.did) const profile = useMaybeProfileShadow(relatedProfiles.get(message.sender.did))
const reactionsControl = useDialogControl() const reactionsControl = useDialogControl()
@@ -433,6 +440,9 @@ let MessageItem = ({
{displayName} {displayName}
</Text> </Text>
) : null} ) : null}
{profile && isBlockedOrBlocking(profile) && isGroupChat ? (
<BlockedPlaceholder profile={profile} style={borderRadiusStyle} />
) : (
<ActionsWrapper <ActionsWrapper
hasReactions={hasReactions} hasReactions={hasReactions}
isFromSelf={isFromSelf} isFromSelf={isFromSelf}
@@ -458,7 +468,9 @@ let MessageItem = ({
a.py_sm, a.py_sm,
a.px_md, a.px_md,
{ {
marginTop: hasEmbedAndText ? CLUSTERED_MESSAGE_GAP : 0, marginTop: hasEmbedAndText
? CLUSTERED_MESSAGE_GAP
: 0,
backgroundColor: isFromSelf backgroundColor: isFromSelf
? isPending ? isPending
? pendingColor ? pendingColor
@@ -497,6 +509,7 @@ let MessageItem = ({
)} )}
{appliedReactions} {appliedReactions}
</ActionsWrapper> </ActionsWrapper>
)}
</View> </View>
</View> </View>
{isLastInCluster && ( {isLastInCluster && (
@@ -560,3 +573,99 @@ let MessageItemMetadata = ({
} }
MessageItemMetadata = memo(MessageItemMetadata) MessageItemMetadata = memo(MessageItemMetadata)
export {MessageItemMetadata} export {MessageItemMetadata}
function BlockedPlaceholder({
profile,
style,
}: {
profile: Shadow<ChatBskyActorDefs.ProfileViewBasic>
style?: StyleProp<ViewStyle>
}) {
const {t: l} = useLingui()
const t = useTheme()
const control = Prompt.usePromptControl()
const [_queueBlock, queueUnblock] = useProfileBlockMutationQueue(profile)
return (
<>
<Button
style={[{maxWidth: '80%'}, a.self_start]}
label={
profile.viewer?.blocking
? l`This message is hidden because you are blocking this user.`
: l`This message is hidden because this user is blocking you.`
}
accessibilityHint={l`Tap for details`}
onPress={() => control.open()}>
<Animated.View
style={[
a.ml_sm,
a.rounded_xl,
a.py_sm,
a.px_md,
t.atoms.bg,
a.self_start,
a.border,
t.atoms.border_contrast_high,
style,
]}>
<Text
style={[
a.text_md,
a.leading_snug,
a.italic,
t.atoms.text_contrast_medium,
]}>
{profile.viewer?.blocking ? (
<Trans>
This message is hidden because you are blocking this user.
</Trans>
) : (
<Trans>
This message is hidden because this user is blocking you.
</Trans>
)}
</Text>
</Animated.View>
</Button>
<Prompt.Outer control={control}>
<Prompt.Content>
<Prompt.TitleText>
{profile.viewer?.blocking ? (
<Trans>
You are blocking {sanitizeHandle(profile.handle, '@')}
</Trans>
) : (
<Trans>
{sanitizeHandle(profile.handle, '@')} is blocking you
</Trans>
)}
</Prompt.TitleText>
<Prompt.DescriptionText>
{profile.viewer?.blocking ? (
<Trans>
Messages from this person are hidden while you are blocking
them.
</Trans>
) : (
<Trans>
Messages from this person are hidden while they are blocking
you.
</Trans>
)}
</Prompt.DescriptionText>
<Prompt.Actions>
<Prompt.Action onPress={() => {}} cta={l`Okay`} color="primary" />
{profile.viewer?.blocking && !profile.viewer.blockingByList && (
<Prompt.Action
onPress={() => queueUnblock()}
cta={l`Unblock`}
color="secondary"
/>
)}
</Prompt.Actions>
</Prompt.Content>
</Prompt.Outer>
</>
)
}