diff --git a/src/components/KeyboardPadding.android.tsx b/src/components/KeyboardPadding.android.tsx new file mode 100644 index 0000000000..40dec30017 --- /dev/null +++ b/src/components/KeyboardPadding.android.tsx @@ -0,0 +1,31 @@ +import React from 'react' +import {useKeyboardHandler} from 'react-native-keyboard-controller' +import Animated, { + useAnimatedStyle, + useSharedValue, +} from 'react-native-reanimated' + +export function KeyboardPadding({maxHeight}: {maxHeight?: number}) { + const keyboardHeight = useSharedValue(0) + + useKeyboardHandler( + { + onMove: e => { + 'worklet' + + if (maxHeight && e.height > maxHeight) { + keyboardHeight.value = maxHeight + } else { + keyboardHeight.value = e.height + } + }, + }, + [maxHeight], + ) + + const animatedStyle = useAnimatedStyle(() => ({ + height: keyboardHeight.value, + })) + + return +} diff --git a/src/components/KeyboardPadding.tsx b/src/components/KeyboardPadding.tsx index 7ecbdf930b..797d42ba0a 100644 --- a/src/components/KeyboardPadding.tsx +++ b/src/components/KeyboardPadding.tsx @@ -1,40 +1,3 @@ -import React from 'react' -import {useKeyboardHandler} from 'react-native-keyboard-controller' -import Animated, { - useAnimatedStyle, - useSharedValue, -} from 'react-native-reanimated' - -import {isAndroid} from 'platform/detection' - -export function KeyboardPadding({androidOnly = true}: {androidOnly?: boolean}) { - if (!isAndroid && androidOnly) { - return null - } - return -} - -function KeyboardPaddingInner({maxHeight}: {maxHeight?: number}) { - const keyboardHeight = useSharedValue(0) - - useKeyboardHandler( - { - onMove: e => { - 'worklet' - - if (maxHeight && e.height > maxHeight) { - keyboardHeight.value = maxHeight - } else { - keyboardHeight.value = e.height - } - }, - }, - [maxHeight], - ) - - const animatedStyle = useAnimatedStyle(() => ({ - height: keyboardHeight.value, - })) - - return +export function KeyboardPadding({maxHeight: _}: {maxHeight?: number}) { + return null } diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx index 281f8609da..2618c51a3d 100644 --- a/src/view/com/composer/Composer.tsx +++ b/src/view/com/composer/Composer.tsx @@ -13,7 +13,10 @@ import { TouchableOpacity, View, } from 'react-native' -import {KeyboardStickyView} from 'react-native-keyboard-controller' +import { + KeyboardAvoidingView, + KeyboardStickyView, +} from 'react-native-keyboard-controller' import Animated, { interpolateColor, useAnimatedStyle, @@ -52,13 +55,14 @@ import {useComposerControls} from '#/state/shell/composer' import {useAnalytics} from 'lib/analytics/analytics' import * as apilib from 'lib/api/index' import {HITSLOP_10, MAX_GRAPHEME_LENGTH} from 'lib/constants' +import {useIsKeyboardVisible} from 'lib/hooks/useIsKeyboardVisible' import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {cleanError} from 'lib/strings/errors' import {insertMentionAt} from 'lib/strings/mention-manip' import {shortenLinks} from 'lib/strings/rich-text-manip' import {colors, gradients, s} from 'lib/styles' -import {isIOS, isNative, isWeb} from 'platform/detection' +import {isAndroid, isIOS, isNative, isWeb} from 'platform/detection' import {useDialogStateControlContext} from 'state/dialogs' import {GalleryModel} from 'state/models/media/gallery' import {ComposerOpts} from 'state/shell/composer' @@ -66,7 +70,6 @@ import {ComposerReplyTo} from 'view/com/composer/ComposerReplyTo' import {atoms as a, useTheme} from '#/alf' import {Button} from '#/components/Button' import {EmojiArc_Stroke2_Corner0_Rounded as EmojiSmile} from '#/components/icons/Emoji' -import {KeyboardPadding} from '#/components/KeyboardPadding' import * as Prompt from '#/components/Prompt' import {QuoteEmbed, QuoteX} from '../util/post-embeds/QuoteEmbed' import {Text} from '../util/text/Text' @@ -122,6 +125,7 @@ export const ComposePost = observer(function ComposePost({ const {closeAllDialogs} = useDialogStateControlContext() const t = useTheme() + const [isKeyboardVisible] = useIsKeyboardVisible({iosUseWillEvents: true}) const [isProcessing, setIsProcessing] = useState(false) const [processingState, setProcessingState] = useState('') const [error, setError] = useState('') @@ -157,6 +161,13 @@ export const ComposePost = observer(function ComposePost({ }, [closeComposer]) const insets = useSafeAreaInsets() + const viewStyles = useMemo( + () => ({ + paddingBottom: + isAndroid || (isIOS && !isKeyboardVisible) ? insets.bottom : 0, + }), + [insets, isKeyboardVisible], + ) const hasScrolled = useSharedValue(0) const scrollHandler = useAnimatedScrollHandler({ @@ -390,174 +401,175 @@ export const ComposePost = observer(function ComposePost({ return ( <> - - - - - Cancel - - - - {isProcessing ? ( - <> - {processingState} - - - - - ) : ( - <> - - {canPost ? ( - - - - {replyTo ? ( - Reply - ) : ( - Post - )} - - - - ) : ( - - - Post - - - )} - - )} - - {isAltTextRequiredAndMissing && ( - - - - - - One or more images is missing alt text. - - - )} - {error !== '' && ( - - - - - {error} - - )} - - {replyTo ? : undefined} - - + + - - - - - - {gallery.isEmpty && extLink && ( - - { - setExtLink(undefined) - setExtGif(undefined) - }} - /> - + hitSlop={HITSLOP_10}> + + Cancel + + + + {isProcessing ? ( + <> + {processingState} + + + + + ) : ( + <> + + {canPost ? ( + + + + {replyTo ? ( + Reply + ) : ( + Post + )} + + + + ) : ( + + + Post + + + )} + + )} + + {isAltTextRequiredAndMissing && ( + + + + + + One or more images is missing alt text. + )} - {quote ? ( - - - + {error !== '' && ( + + + - {quote.uri !== initQuote?.uri && ( - setQuote(undefined)} /> - )} + {error} - ) : undefined} - - - - + )} + + {replyTo ? : undefined} + + + + + + + + {gallery.isEmpty && extLink && ( + + { + setExtLink(undefined) + setExtGif(undefined) + }} + /> + + + )} + {quote ? ( + + + + + {quote.uri !== initQuote?.uri && ( + setQuote(undefined)} /> + )} + + ) : undefined} + + + + {replyTo ? null : (