diff --git a/src/components/HeaderWithBackButton/index.tsx b/src/components/HeaderWithBackButton/index.tsx index 2c07c48d52b7..6fa006cfb4fb 100755 --- a/src/components/HeaderWithBackButton/index.tsx +++ b/src/components/HeaderWithBackButton/index.tsx @@ -10,7 +10,6 @@ import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeed import SearchButton from '@components/Search/SearchRouter/SearchButton'; import ThreeDotsMenu from '@components/ThreeDotsMenu'; import Tooltip from '@components/Tooltip'; -import useKeyboardState from '@hooks/useKeyboardState'; import useLocalize from '@hooks/useLocalize'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; @@ -72,7 +71,6 @@ function HeaderWithBackButton({ const StyleUtils = useStyleUtils(); const [isDownloadButtonActive, temporarilyDisableDownloadButton] = useThrottledButtonState(); const {translate} = useLocalize(); - const {isKeyboardShown} = useKeyboardState(); // If the icon is present, the header bar should be taller and use different font. const isCentralPaneSettings = !!icon; @@ -155,7 +153,7 @@ function HeaderWithBackButton({ { - if (isKeyboardShown) { + if (Keyboard.isVisible()) { Keyboard.dismiss(); } const topmostReportId = Navigation.getTopmostReportId(); diff --git a/src/components/KeyboardAvoidingView/index.android.tsx b/src/components/KeyboardAvoidingView/index.android.tsx index 4d758511d7ad..68cfa73e90b5 100644 --- a/src/components/KeyboardAvoidingView/index.android.tsx +++ b/src/components/KeyboardAvoidingView/index.android.tsx @@ -1,133 +1,15 @@ -import React, {forwardRef, useCallback, useMemo, useState} from 'react'; -import type {LayoutRectangle, View, ViewProps} from 'react-native'; -import {useKeyboardContext, useKeyboardHandler} from 'react-native-keyboard-controller'; -import Reanimated, {interpolate, runOnUI, useAnimatedStyle, useDerivedValue, useSharedValue} from 'react-native-reanimated'; -import {useSafeAreaFrame} from 'react-native-safe-area-context'; -import type {KeyboardAvoidingViewProps} from './types'; - -const useKeyboardAnimation = () => { - const {reanimated} = useKeyboardContext(); - - // calculate it only once on mount, to avoid `SharedValue` reads during a render - const [initialHeight] = useState(() => -reanimated.height.get()); - const [initialProgress] = useState(() => reanimated.progress.get()); - - const heightWhenOpened = useSharedValue(initialHeight); - const height = useSharedValue(initialHeight); - const progress = useSharedValue(initialProgress); - const isClosed = useSharedValue(initialProgress === 0); - - useKeyboardHandler( - { - onStart: (e) => { - 'worklet'; - - progress.set(e.progress); - height.set(e.height); - - if (e.height > 0) { - isClosed.set(false); - heightWhenOpened.set(e.height); - } - }, - onEnd: (e) => { - 'worklet'; - - isClosed.set(e.height === 0); - height.set(e.height); - progress.set(e.progress); - }, - }, - [], - ); - - return {height, progress, heightWhenOpened, isClosed}; -}; - -const defaultLayout: LayoutRectangle = { - x: 0, - y: 0, - width: 0, - height: 0, -}; - -/** - * View that moves out of the way when the keyboard appears by automatically - * adjusting its height, position, or bottom padding. - * - * This `KeyboardAvoidingView` acts as a backward compatible layer for the previous Android behavior (prior to edge-to-edge mode). - * We can use `KeyboardAvoidingView` directly from the `react-native-keyboard-controller` package, but in this case animations are stuttering and it's better to handle as a separate task. +/* + * The KeyboardAvoidingView is only used on ios */ -const KeyboardAvoidingView = forwardRef>( - ({behavior, children, contentContainerStyle, enabled = true, keyboardVerticalOffset = 0, style, onLayout: onLayoutProps, ...props}, ref) => { - const initialFrame = useSharedValue(null); - const frame = useDerivedValue(() => initialFrame.get() ?? defaultLayout); - - const keyboard = useKeyboardAnimation(); - const {height: screenHeight} = useSafeAreaFrame(); - - const relativeKeyboardHeight = useCallback(() => { - 'worklet'; - - const keyboardY = screenHeight - keyboard.heightWhenOpened.get() - keyboardVerticalOffset; - - return Math.max(frame.get().y + frame.get().height - keyboardY, 0); - }, [screenHeight, keyboard.heightWhenOpened, keyboardVerticalOffset, frame]); - - const onLayoutWorklet = useCallback( - (layout: LayoutRectangle) => { - 'worklet'; - - if (keyboard.isClosed.get() || initialFrame.get() === null) { - initialFrame.set(layout); - } - }, - [initialFrame, keyboard.isClosed], - ); - const onLayout = useCallback>( - (e) => { - runOnUI(onLayoutWorklet)(e.nativeEvent.layout); - onLayoutProps?.(e); - }, - [onLayoutProps, onLayoutWorklet], - ); - - const animatedStyle = useAnimatedStyle(() => { - const bottom = interpolate(keyboard.progress.get(), [0, 1], [0, relativeKeyboardHeight()]); - const bottomHeight = enabled ? bottom : 0; - - switch (behavior) { - case 'height': - if (!keyboard.isClosed.get()) { - return { - height: frame.get().height - bottomHeight, - flex: 0, - }; - } - - return {}; - - case 'padding': - return {paddingBottom: bottomHeight}; +import React from 'react'; +import {KeyboardAvoidingView as KeyboardAvoidingViewComponent} from 'react-native-keyboard-controller'; +import type {KeyboardAvoidingViewProps} from './types'; - default: - return {}; - } - }, [behavior, enabled, relativeKeyboardHeight]); - const combinedStyles = useMemo(() => [style, animatedStyle], [style, animatedStyle]); +function KeyboardAvoidingView(props: KeyboardAvoidingViewProps) { + // eslint-disable-next-line react/jsx-props-no-spreading + return ; +} - return ( - - {children} - - ); - }, -); +KeyboardAvoidingView.displayName = 'KeyboardAvoidingView'; export default KeyboardAvoidingView; diff --git a/src/components/ScreenWrapper.tsx b/src/components/ScreenWrapper.tsx index 09315bfb8a8e..bb20b4abae11 100644 --- a/src/components/ScreenWrapper.tsx +++ b/src/components/ScreenWrapper.tsx @@ -7,7 +7,6 @@ import {PickerAvoidingView} from 'react-native-picker-select'; import type {EdgeInsets} from 'react-native-safe-area-context'; import useEnvironment from '@hooks/useEnvironment'; import useInitialDimensions from '@hooks/useInitialWindowDimensions'; -import useKeyboardState from '@hooks/useKeyboardState'; import useNetwork from '@hooks/useNetwork'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useStyledSafeAreaInsets from '@hooks/useStyledSafeAreaInsets'; @@ -158,18 +157,11 @@ function ScreenWrapper( const {isSmallScreenWidth, shouldUseNarrowLayout} = useResponsiveLayout(); const {initialHeight} = useInitialDimensions(); const styles = useThemeStyles(); - const keyboardState = useKeyboardState(); const {isDevelopment} = useEnvironment(); const {isOffline} = useNetwork(); const [didScreenTransitionEnd, setDidScreenTransitionEnd] = useState(false); const maxHeight = shouldEnableMaxHeight ? windowHeight : undefined; const minHeight = shouldEnableMinHeight && !Browser.isSafari() ? initialHeight : undefined; - const isKeyboardShown = keyboardState?.isKeyboardShown ?? false; - - const isKeyboardShownRef = useRef(false); - - // eslint-disable-next-line react-compiler/react-compiler - isKeyboardShownRef.current = keyboardState?.isKeyboardShown ?? false; const route = useRoute(); const shouldReturnToOldDot = useMemo(() => { @@ -191,7 +183,7 @@ function ScreenWrapper( PanResponder.create({ onMoveShouldSetPanResponderCapture: (_e, gestureState) => { const isHorizontalSwipe = Math.abs(gestureState.dx) > Math.abs(gestureState.dy); - const shouldDismissKeyboard = shouldDismissKeyboardBeforeClose && isKeyboardShown && Browser.isMobile(); + const shouldDismissKeyboard = shouldDismissKeyboardBeforeClose && Keyboard.isVisible() && Browser.isMobile(); return isHorizontalSwipe && shouldDismissKeyboard; }, @@ -221,7 +213,7 @@ function ScreenWrapper( // described here https://reactnavigation.org/docs/preventing-going-back/#limitations const beforeRemoveSubscription = shouldDismissKeyboardBeforeClose ? navigation.addListener('beforeRemove', () => { - if (!isKeyboardShownRef.current) { + if (!Keyboard.isVisible()) { return; } Keyboard.dismiss(); diff --git a/src/components/withKeyboardState.tsx b/src/components/withKeyboardState.tsx index 72540ebceaa8..1ae6a64742de 100755 --- a/src/components/withKeyboardState.tsx +++ b/src/components/withKeyboardState.tsx @@ -1,7 +1,6 @@ -import type {ComponentType, ForwardedRef, ReactElement, RefAttributes} from 'react'; -import React, {createContext, forwardRef, useEffect, useMemo, useState} from 'react'; +import type {ReactElement} from 'react'; +import React, {createContext, useEffect, useMemo, useState} from 'react'; import {Keyboard} from 'react-native'; -import getComponentDisplayName from '@libs/getComponentDisplayName'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; type KeyboardStateContextValue = { @@ -44,27 +43,5 @@ function KeyboardStateProvider({children}: ChildrenProps): ReactElement | null { return {children}; } -export default function withKeyboardState( - WrappedComponent: ComponentType>, -): (props: Omit & React.RefAttributes) => ReactElement | null { - function WithKeyboardState(props: Omit, ref: ForwardedRef) { - return ( - - {(keyboardStateProps) => ( - - )} - - ); - } - WithKeyboardState.displayName = `withKeyboardState(${getComponentDisplayName(WrappedComponent)})`; - return forwardRef(WithKeyboardState); -} - export type {KeyboardStateContextValue}; export {KeyboardStateProvider, KeyboardStateContext};