diff options
Diffstat (limited to 'src/view/com/post-thread/PostThread.tsx')
-rw-r--r-- | src/view/com/post-thread/PostThread.tsx | 48 |
1 files changed, 36 insertions, 12 deletions
diff --git a/src/view/com/post-thread/PostThread.tsx b/src/view/com/post-thread/PostThread.tsx index b7eaedd36..401457412 100644 --- a/src/view/com/post-thread/PostThread.tsx +++ b/src/view/com/post-thread/PostThread.tsx @@ -1,11 +1,14 @@ -import React, {useEffect, useRef} from 'react' -import {useWindowDimensions, View} from 'react-native' +import React, {useRef} from 'react' +import {StyleSheet, useWindowDimensions, View} from 'react-native' import {runOnJS} from 'react-native-reanimated' +import Animated from 'react-native-reanimated' +import {useSafeAreaInsets} from 'react-native-safe-area-context' import {AppBskyFeedDefs} from '@atproto/api' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {moderatePost_wrapped as moderatePost} from '#/lib/moderatePost_wrapped' +import {clamp} from '#/lib/numbers' import {ScrollProvider} from '#/lib/ScrollContext' import {isAndroid, isNative, isWeb} from '#/platform/detection' import {useModerationOpts} from '#/state/preferences/moderation-opts' @@ -22,6 +25,7 @@ import { import {usePreferencesQuery} from '#/state/queries/preferences' import {useSession} from '#/state/session' import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender' +import {useMinimalShellFabTransform} from 'lib/hooks/useMinimalShellTransform' import {useSetTitle} from 'lib/hooks/useSetTitle' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {sanitizeDisplayName} from 'lib/strings/display-names' @@ -82,11 +86,9 @@ const keyExtractor = (item: RowItem) => { export function PostThread({ uri, - onCanReply, onPressReply, }: { uri: string | undefined - onCanReply: (canReply: boolean) => void onPressReply: () => unknown }) { const {hasSession, currentAccount} = useSession() @@ -210,14 +212,6 @@ export function PostThread({ return null }, [thread, skeleton?.highlightedPost, isThreadError, _, threadError]) - useEffect(() => { - if (error) { - onCanReply(false) - } else if (rootPost) { - onCanReply(!rootPost.viewer?.replyDisabled) - } - }, [rootPost, onCanReply, error]) - // construct content const posts = React.useMemo(() => { if (!skeleton) return [] @@ -313,6 +307,7 @@ export function PostThread({ setMaxReplies(prev => prev + 50) }, [isFetching, maxReplies, posts.length]) + const canReply = !error && rootPost && !rootPost.viewer?.replyDisabled const hasParents = skeleton?.highlightedPost?.type === 'post' && (skeleton.highlightedPost.ctx.isParentLoading || @@ -473,10 +468,30 @@ export function PostThread({ sideBorders={false} /> </ScrollProvider> + {isMobile && canReply && hasSession && ( + <MobileComposePrompt onPressReply={onPressReply} /> + )} </CenteredView> ) } +function MobileComposePrompt({onPressReply}: {onPressReply: () => unknown}) { + const safeAreaInsets = useSafeAreaInsets() + const fabMinimalShellTransform = useMinimalShellFabTransform() + return ( + <Animated.View + style={[ + styles.prompt, + fabMinimalShellTransform, + { + bottom: clamp(safeAreaInsets.bottom, 15, 30), + }, + ]}> + <ComposePrompt onPressCompose={onPressReply} /> + </Animated.View> + ) +} + function isThreadPost(v: unknown): v is ThreadPost { return !!v && typeof v === 'object' && 'type' in v && v.type === 'post' } @@ -622,3 +637,12 @@ function hasBranchingReplies(node?: ThreadNode) { } return true } + +const styles = StyleSheet.create({ + prompt: { + // @ts-ignore web-only + position: isWeb ? 'fixed' : 'absolute', + left: 0, + right: 0, + }, +}) |