Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Composer blocks (#5040)

* Move i18n provider up the stack

* Protect composer opening for a blocked post

* Protect ctrls from interacting with blocked user

authored by

Eric Bailey and committed by
GitHub
c60e8d07 dbbbba1d

+93 -45
+20 -20
src/App.native.tsx
··· 172 172 * that is set up in the InnerApp component above. 173 173 */ 174 174 return ( 175 - <A11yProvider> 176 - <KeyboardProvider enabled={false} statusBarTranslucent={true}> 177 - <SessionProvider> 178 - <ShellStateProvider> 179 - <PrefsStateProvider> 180 - <InvitesStateProvider> 181 - <ModalStateProvider> 182 - <DialogStateProvider> 183 - <LightboxStateProvider> 184 - <I18nProvider> 175 + <I18nProvider> 176 + <A11yProvider> 177 + <KeyboardProvider enabled={false} statusBarTranslucent={true}> 178 + <SessionProvider> 179 + <ShellStateProvider> 180 + <PrefsStateProvider> 181 + <InvitesStateProvider> 182 + <ModalStateProvider> 183 + <DialogStateProvider> 184 + <LightboxStateProvider> 185 185 <PortalProvider> 186 186 <StarterPackProvider> 187 187 <InnerApp /> 188 188 </StarterPackProvider> 189 189 </PortalProvider> 190 - </I18nProvider> 191 - </LightboxStateProvider> 192 - </DialogStateProvider> 193 - </ModalStateProvider> 194 - </InvitesStateProvider> 195 - </PrefsStateProvider> 196 - </ShellStateProvider> 197 - </SessionProvider> 198 - </KeyboardProvider> 199 - </A11yProvider> 190 + </LightboxStateProvider> 191 + </DialogStateProvider> 192 + </ModalStateProvider> 193 + </InvitesStateProvider> 194 + </PrefsStateProvider> 195 + </ShellStateProvider> 196 + </SessionProvider> 197 + </KeyboardProvider> 198 + </A11yProvider> 199 + </I18nProvider> 200 200 ) 201 201 } 202 202
+18 -18
src/App.web.tsx
··· 151 151 * that is set up in the InnerApp component above. 152 152 */ 153 153 return ( 154 - <A11yProvider> 155 - <SessionProvider> 156 - <ShellStateProvider> 157 - <PrefsStateProvider> 158 - <InvitesStateProvider> 159 - <ModalStateProvider> 160 - <DialogStateProvider> 161 - <LightboxStateProvider> 162 - <I18nProvider> 154 + <I18nProvider> 155 + <A11yProvider> 156 + <SessionProvider> 157 + <ShellStateProvider> 158 + <PrefsStateProvider> 159 + <InvitesStateProvider> 160 + <ModalStateProvider> 161 + <DialogStateProvider> 162 + <LightboxStateProvider> 163 163 <PortalProvider> 164 164 <StarterPackProvider> 165 165 <InnerApp /> 166 166 </StarterPackProvider> 167 167 </PortalProvider> 168 - </I18nProvider> 169 - </LightboxStateProvider> 170 - </DialogStateProvider> 171 - </ModalStateProvider> 172 - </InvitesStateProvider> 173 - </PrefsStateProvider> 174 - </ShellStateProvider> 175 - </SessionProvider> 176 - </A11yProvider> 168 + </LightboxStateProvider> 169 + </DialogStateProvider> 170 + </ModalStateProvider> 171 + </InvitesStateProvider> 172 + </PrefsStateProvider> 173 + </ShellStateProvider> 174 + </SessionProvider> 175 + </A11yProvider> 176 + </I18nProvider> 177 177 ) 178 178 } 179 179
+20 -7
src/state/shell/composer.tsx
··· 5 5 AppBskyRichtextFacet, 6 6 ModerationDecision, 7 7 } from '@atproto/api' 8 + import {msg} from '@lingui/macro' 9 + import {useLingui} from '@lingui/react' 8 10 9 11 import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' 12 + import * as Toast from '#/view/com/util/Toast' 10 13 11 14 export interface ComposerOptsPostRef { 12 15 uri: string ··· 22 25 text: string 23 26 facets?: AppBskyRichtextFacet.Main[] 24 27 indexedAt: string 25 - author: { 26 - did: string 27 - handle: string 28 - displayName?: string 29 - avatar?: string 30 - } 28 + author: AppBskyActorDefs.ProfileViewBasic 31 29 embeds?: AppBskyEmbedRecord.ViewRecord['embeds'] 32 30 } 33 31 export interface ComposerOpts { ··· 56 54 }) 57 55 58 56 export function Provider({children}: React.PropsWithChildren<{}>) { 57 + const {_} = useLingui() 59 58 const [state, setState] = React.useState<StateContext>() 60 59 61 60 const openComposer = useNonReactiveCallback((opts: ComposerOpts) => { 62 - setState(opts) 61 + const author = opts.replyTo?.author || opts.quote?.author 62 + const isBlocked = Boolean( 63 + author && 64 + (author.viewer?.blocking || 65 + author.viewer?.blockedBy || 66 + author.viewer?.blockingByList), 67 + ) 68 + if (isBlocked) { 69 + Toast.show( 70 + _(msg`Cannot interact with a blocked user`), 71 + 'exclamation-circle', 72 + ) 73 + } else { 74 + setState(opts) 75 + } 63 76 }) 64 77 65 78 const closeComposer = useNonReactiveCallback(() => {
+35
src/view/com/util/post-ctrls/PostCtrls.tsx
··· 89 89 const {captureAction} = useProgressGuideControls() 90 90 const playHaptic = useHaptics() 91 91 const gate = useGate() 92 + const isBlocked = Boolean( 93 + post.author.viewer?.blocking || 94 + post.author.viewer?.blockedBy || 95 + post.author.viewer?.blockingByList, 96 + ) 92 97 93 98 const shouldShowLoggedOutWarning = React.useMemo(() => { 94 99 return ( ··· 105 110 ) as StyleProp<ViewStyle> 106 111 107 112 const onPressToggleLike = React.useCallback(async () => { 113 + if (isBlocked) { 114 + Toast.show( 115 + _(msg`Cannot interact with a blocked user`), 116 + 'exclamation-circle', 117 + ) 118 + return 119 + } 120 + 108 121 try { 109 122 if (!post.viewer?.like) { 110 123 playHaptic() ··· 124 137 } 125 138 } 126 139 }, [ 140 + _, 127 141 playHaptic, 128 142 post.uri, 129 143 post.viewer?.like, ··· 132 146 sendInteraction, 133 147 captureAction, 134 148 feedContext, 149 + isBlocked, 135 150 ]) 136 151 137 152 const onRepost = useCallback(async () => { 153 + if (isBlocked) { 154 + Toast.show( 155 + _(msg`Cannot interact with a blocked user`), 156 + 'exclamation-circle', 157 + ) 158 + return 159 + } 160 + 138 161 try { 139 162 if (!post.viewer?.repost) { 140 163 sendInteraction({ ··· 152 175 } 153 176 } 154 177 }, [ 178 + _, 155 179 post.uri, 156 180 post.viewer?.repost, 157 181 queueRepost, 158 182 queueUnrepost, 159 183 sendInteraction, 160 184 feedContext, 185 + isBlocked, 161 186 ]) 162 187 163 188 const onQuote = useCallback(() => { 189 + if (isBlocked) { 190 + Toast.show( 191 + _(msg`Cannot interact with a blocked user`), 192 + 'exclamation-circle', 193 + ) 194 + return 195 + } 196 + 164 197 sendInteraction({ 165 198 item: post.uri, 166 199 event: 'app.bsky.feed.defs#interactionQuote', ··· 178 211 onPost: onPostReply, 179 212 }) 180 213 }, [ 214 + _, 181 215 sendInteraction, 182 216 post.uri, 183 217 post.cid, ··· 188 222 openComposer, 189 223 record.text, 190 224 onPostReply, 225 + isBlocked, 191 226 ]) 192 227 193 228 const onShare = useCallback(() => {