Composer blocks (#5040)

* Move i18n provider up the stack

* Protect composer opening for a blocked post

* Protect ctrls from interacting with blocked user
zio/stable
Eric Bailey 2024-08-30 12:26:40 -05:00 committed by GitHub
parent dbbbba1d32
commit c60e8d0772
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 93 additions and 45 deletions

View File

@ -172,31 +172,31 @@ function App() {
* that is set up in the InnerApp component above. * that is set up in the InnerApp component above.
*/ */
return ( return (
<A11yProvider> <I18nProvider>
<KeyboardProvider enabled={false} statusBarTranslucent={true}> <A11yProvider>
<SessionProvider> <KeyboardProvider enabled={false} statusBarTranslucent={true}>
<ShellStateProvider> <SessionProvider>
<PrefsStateProvider> <ShellStateProvider>
<InvitesStateProvider> <PrefsStateProvider>
<ModalStateProvider> <InvitesStateProvider>
<DialogStateProvider> <ModalStateProvider>
<LightboxStateProvider> <DialogStateProvider>
<I18nProvider> <LightboxStateProvider>
<PortalProvider> <PortalProvider>
<StarterPackProvider> <StarterPackProvider>
<InnerApp /> <InnerApp />
</StarterPackProvider> </StarterPackProvider>
</PortalProvider> </PortalProvider>
</I18nProvider> </LightboxStateProvider>
</LightboxStateProvider> </DialogStateProvider>
</DialogStateProvider> </ModalStateProvider>
</ModalStateProvider> </InvitesStateProvider>
</InvitesStateProvider> </PrefsStateProvider>
</PrefsStateProvider> </ShellStateProvider>
</ShellStateProvider> </SessionProvider>
</SessionProvider> </KeyboardProvider>
</KeyboardProvider> </A11yProvider>
</A11yProvider> </I18nProvider>
) )
} }

View File

@ -151,29 +151,29 @@ function App() {
* that is set up in the InnerApp component above. * that is set up in the InnerApp component above.
*/ */
return ( return (
<A11yProvider> <I18nProvider>
<SessionProvider> <A11yProvider>
<ShellStateProvider> <SessionProvider>
<PrefsStateProvider> <ShellStateProvider>
<InvitesStateProvider> <PrefsStateProvider>
<ModalStateProvider> <InvitesStateProvider>
<DialogStateProvider> <ModalStateProvider>
<LightboxStateProvider> <DialogStateProvider>
<I18nProvider> <LightboxStateProvider>
<PortalProvider> <PortalProvider>
<StarterPackProvider> <StarterPackProvider>
<InnerApp /> <InnerApp />
</StarterPackProvider> </StarterPackProvider>
</PortalProvider> </PortalProvider>
</I18nProvider> </LightboxStateProvider>
</LightboxStateProvider> </DialogStateProvider>
</DialogStateProvider> </ModalStateProvider>
</ModalStateProvider> </InvitesStateProvider>
</InvitesStateProvider> </PrefsStateProvider>
</PrefsStateProvider> </ShellStateProvider>
</ShellStateProvider> </SessionProvider>
</SessionProvider> </A11yProvider>
</A11yProvider> </I18nProvider>
) )
} }

View File

@ -5,8 +5,11 @@ import {
AppBskyRichtextFacet, AppBskyRichtextFacet,
ModerationDecision, ModerationDecision,
} from '@atproto/api' } from '@atproto/api'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
import * as Toast from '#/view/com/util/Toast'
export interface ComposerOptsPostRef { export interface ComposerOptsPostRef {
uri: string uri: string
@ -22,12 +25,7 @@ export interface ComposerOptsQuote {
text: string text: string
facets?: AppBskyRichtextFacet.Main[] facets?: AppBskyRichtextFacet.Main[]
indexedAt: string indexedAt: string
author: { author: AppBskyActorDefs.ProfileViewBasic
did: string
handle: string
displayName?: string
avatar?: string
}
embeds?: AppBskyEmbedRecord.ViewRecord['embeds'] embeds?: AppBskyEmbedRecord.ViewRecord['embeds']
} }
export interface ComposerOpts { export interface ComposerOpts {
@ -56,10 +54,25 @@ const controlsContext = React.createContext<ControlsContext>({
}) })
export function Provider({children}: React.PropsWithChildren<{}>) { export function Provider({children}: React.PropsWithChildren<{}>) {
const {_} = useLingui()
const [state, setState] = React.useState<StateContext>() const [state, setState] = React.useState<StateContext>()
const openComposer = useNonReactiveCallback((opts: ComposerOpts) => { const openComposer = useNonReactiveCallback((opts: ComposerOpts) => {
setState(opts) const author = opts.replyTo?.author || opts.quote?.author
const isBlocked = Boolean(
author &&
(author.viewer?.blocking ||
author.viewer?.blockedBy ||
author.viewer?.blockingByList),
)
if (isBlocked) {
Toast.show(
_(msg`Cannot interact with a blocked user`),
'exclamation-circle',
)
} else {
setState(opts)
}
}) })
const closeComposer = useNonReactiveCallback(() => { const closeComposer = useNonReactiveCallback(() => {

View File

@ -89,6 +89,11 @@ let PostCtrls = ({
const {captureAction} = useProgressGuideControls() const {captureAction} = useProgressGuideControls()
const playHaptic = useHaptics() const playHaptic = useHaptics()
const gate = useGate() const gate = useGate()
const isBlocked = Boolean(
post.author.viewer?.blocking ||
post.author.viewer?.blockedBy ||
post.author.viewer?.blockingByList,
)
const shouldShowLoggedOutWarning = React.useMemo(() => { const shouldShowLoggedOutWarning = React.useMemo(() => {
return ( return (
@ -105,6 +110,14 @@ let PostCtrls = ({
) as StyleProp<ViewStyle> ) as StyleProp<ViewStyle>
const onPressToggleLike = React.useCallback(async () => { const onPressToggleLike = React.useCallback(async () => {
if (isBlocked) {
Toast.show(
_(msg`Cannot interact with a blocked user`),
'exclamation-circle',
)
return
}
try { try {
if (!post.viewer?.like) { if (!post.viewer?.like) {
playHaptic() playHaptic()
@ -124,6 +137,7 @@ let PostCtrls = ({
} }
} }
}, [ }, [
_,
playHaptic, playHaptic,
post.uri, post.uri,
post.viewer?.like, post.viewer?.like,
@ -132,9 +146,18 @@ let PostCtrls = ({
sendInteraction, sendInteraction,
captureAction, captureAction,
feedContext, feedContext,
isBlocked,
]) ])
const onRepost = useCallback(async () => { const onRepost = useCallback(async () => {
if (isBlocked) {
Toast.show(
_(msg`Cannot interact with a blocked user`),
'exclamation-circle',
)
return
}
try { try {
if (!post.viewer?.repost) { if (!post.viewer?.repost) {
sendInteraction({ sendInteraction({
@ -152,15 +175,25 @@ let PostCtrls = ({
} }
} }
}, [ }, [
_,
post.uri, post.uri,
post.viewer?.repost, post.viewer?.repost,
queueRepost, queueRepost,
queueUnrepost, queueUnrepost,
sendInteraction, sendInteraction,
feedContext, feedContext,
isBlocked,
]) ])
const onQuote = useCallback(() => { const onQuote = useCallback(() => {
if (isBlocked) {
Toast.show(
_(msg`Cannot interact with a blocked user`),
'exclamation-circle',
)
return
}
sendInteraction({ sendInteraction({
item: post.uri, item: post.uri,
event: 'app.bsky.feed.defs#interactionQuote', event: 'app.bsky.feed.defs#interactionQuote',
@ -178,6 +211,7 @@ let PostCtrls = ({
onPost: onPostReply, onPost: onPostReply,
}) })
}, [ }, [
_,
sendInteraction, sendInteraction,
post.uri, post.uri,
post.cid, post.cid,
@ -188,6 +222,7 @@ let PostCtrls = ({
openComposer, openComposer,
record.text, record.text,
onPostReply, onPostReply,
isBlocked,
]) ])
const onShare = useCallback(() => { const onShare = useCallback(() => {