Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

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

Remove unnecessary state update for reply gate (#4897)

* Move mobile compose prompt to inner component

* Make canReply computed

* Use same clamp we use elsewhere

authored by

dan and committed by
GitHub
4b71950d 2174feed

+38 -52
+36 -12
src/view/com/post-thread/PostThread.tsx
··· 1 - import React, {useEffect, useRef} from 'react' 2 - import {useWindowDimensions, View} from 'react-native' 1 + import React, {useRef} from 'react' 2 + import {StyleSheet, useWindowDimensions, View} from 'react-native' 3 3 import {runOnJS} from 'react-native-reanimated' 4 + import Animated from 'react-native-reanimated' 5 + import {useSafeAreaInsets} from 'react-native-safe-area-context' 4 6 import {AppBskyFeedDefs} from '@atproto/api' 5 7 import {msg, Trans} from '@lingui/macro' 6 8 import {useLingui} from '@lingui/react' 7 9 8 10 import {moderatePost_wrapped as moderatePost} from '#/lib/moderatePost_wrapped' 11 + import {clamp} from '#/lib/numbers' 9 12 import {ScrollProvider} from '#/lib/ScrollContext' 10 13 import {isAndroid, isNative, isWeb} from '#/platform/detection' 11 14 import {useModerationOpts} from '#/state/preferences/moderation-opts' ··· 22 25 import {usePreferencesQuery} from '#/state/queries/preferences' 23 26 import {useSession} from '#/state/session' 24 27 import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender' 28 + import {useMinimalShellFabTransform} from 'lib/hooks/useMinimalShellTransform' 25 29 import {useSetTitle} from 'lib/hooks/useSetTitle' 26 30 import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' 27 31 import {sanitizeDisplayName} from 'lib/strings/display-names' ··· 82 86 83 87 export function PostThread({ 84 88 uri, 85 - onCanReply, 86 89 onPressReply, 87 90 }: { 88 91 uri: string | undefined 89 - onCanReply: (canReply: boolean) => void 90 92 onPressReply: () => unknown 91 93 }) { 92 94 const {hasSession, currentAccount} = useSession() ··· 210 212 return null 211 213 }, [thread, skeleton?.highlightedPost, isThreadError, _, threadError]) 212 214 213 - useEffect(() => { 214 - if (error) { 215 - onCanReply(false) 216 - } else if (rootPost) { 217 - onCanReply(!rootPost.viewer?.replyDisabled) 218 - } 219 - }, [rootPost, onCanReply, error]) 220 - 221 215 // construct content 222 216 const posts = React.useMemo(() => { 223 217 if (!skeleton) return [] ··· 313 307 setMaxReplies(prev => prev + 50) 314 308 }, [isFetching, maxReplies, posts.length]) 315 309 310 + const canReply = !error && rootPost && !rootPost.viewer?.replyDisabled 316 311 const hasParents = 317 312 skeleton?.highlightedPost?.type === 'post' && 318 313 (skeleton.highlightedPost.ctx.isParentLoading || ··· 473 468 sideBorders={false} 474 469 /> 475 470 </ScrollProvider> 471 + {isMobile && canReply && hasSession && ( 472 + <MobileComposePrompt onPressReply={onPressReply} /> 473 + )} 476 474 </CenteredView> 477 475 ) 478 476 } 479 477 478 + function MobileComposePrompt({onPressReply}: {onPressReply: () => unknown}) { 479 + const safeAreaInsets = useSafeAreaInsets() 480 + const fabMinimalShellTransform = useMinimalShellFabTransform() 481 + return ( 482 + <Animated.View 483 + style={[ 484 + styles.prompt, 485 + fabMinimalShellTransform, 486 + { 487 + bottom: clamp(safeAreaInsets.bottom, 15, 30), 488 + }, 489 + ]}> 490 + <ComposePrompt onPressCompose={onPressReply} /> 491 + </Animated.View> 492 + ) 493 + } 494 + 480 495 function isThreadPost(v: unknown): v is ThreadPost { 481 496 return !!v && typeof v === 'object' && 'type' in v && v.type === 'post' 482 497 } ··· 622 637 } 623 638 return true 624 639 } 640 + 641 + const styles = StyleSheet.create({ 642 + prompt: { 643 + // @ts-ignore web-only 644 + position: isWeb ? 'fixed' : 'absolute', 645 + left: 0, 646 + right: 0, 647 + }, 648 + })
+2 -40
src/view/screens/PostThread.tsx
··· 1 1 import React from 'react' 2 - import {StyleSheet, View} from 'react-native' 3 - import Animated from 'react-native-reanimated' 4 - import {useSafeAreaInsets} from 'react-native-safe-area-context' 2 + import {View} from 'react-native' 5 3 import {useFocusEffect} from '@react-navigation/native' 6 4 import {useQueryClient} from '@tanstack/react-query' 7 - import {clamp} from 'lodash' 8 5 9 - import {isWeb} from '#/platform/detection' 10 6 import { 11 7 RQKEY as POST_THREAD_RQKEY, 12 8 ThreadNode, 13 9 } from '#/state/queries/post-thread' 14 - import {useSession} from '#/state/session' 15 10 import {useSetMinimalShellMode} from '#/state/shell' 16 11 import {useComposerControls} from '#/state/shell/composer' 17 - import {useMinimalShellFabTransform} from 'lib/hooks/useMinimalShellTransform' 18 - import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' 19 12 import {CommonNavigatorParams, NativeStackScreenProps} from 'lib/routes/types' 20 13 import {makeRecordUri} from 'lib/strings/url-helpers' 21 14 import {s} from 'lib/styles' 22 - import {ComposePrompt} from 'view/com/composer/Prompt' 23 15 import {PostThread as PostThreadComponent} from '../com/post-thread/PostThread' 24 16 25 17 type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostThread'> 26 18 export function PostThreadScreen({route}: Props) { 27 19 const queryClient = useQueryClient() 28 - const {hasSession} = useSession() 29 - const fabMinimalShellTransform = useMinimalShellFabTransform() 30 20 const setMinimalShellMode = useSetMinimalShellMode() 31 21 const {openComposer} = useComposerControls() 32 - const safeAreaInsets = useSafeAreaInsets() 33 22 const {name, rkey} = route.params 34 - const {isMobile} = useWebMediaQueries() 35 23 const uri = makeRecordUri(name, 'app.bsky.feed.post', rkey) 36 - const [canReply, setCanReply] = React.useState(false) 37 24 38 25 useFocusEffect( 39 26 React.useCallback(() => { ··· 67 54 return ( 68 55 <View style={s.hContentRegion}> 69 56 <View style={s.flex1}> 70 - <PostThreadComponent 71 - uri={uri} 72 - onPressReply={onPressReply} 73 - onCanReply={setCanReply} 74 - /> 57 + <PostThreadComponent uri={uri} onPressReply={onPressReply} /> 75 58 </View> 76 - {isMobile && canReply && hasSession && ( 77 - <Animated.View 78 - style={[ 79 - styles.prompt, 80 - fabMinimalShellTransform, 81 - { 82 - bottom: clamp(safeAreaInsets.bottom, 15, 30), 83 - }, 84 - ]}> 85 - <ComposePrompt onPressCompose={onPressReply} /> 86 - </Animated.View> 87 - )} 88 59 </View> 89 60 ) 90 61 } 91 - 92 - const styles = StyleSheet.create({ 93 - prompt: { 94 - // @ts-ignore web-only 95 - position: isWeb ? 'fixed' : 'absolute', 96 - left: 0, 97 - right: 0, 98 - }, 99 - })