diff --git a/native/account/logged-out-modal.react.js b/native/account/logged-out-modal.react.js --- a/native/account/logged-out-modal.react.js +++ b/native/account/logged-out-modal.react.js @@ -1,7 +1,6 @@ // @flow import Icon from '@expo/vector-icons/FontAwesome.js'; -import _isEqual from 'lodash/fp/isEqual.js'; import * as React from 'react'; import { View, @@ -34,11 +33,7 @@ import { authoritativeKeyserverID } from '../authoritative-keyserver.js'; import KeyboardAvoidingView from '../components/keyboard-avoiding-view.react.js'; import ConnectedStatusBar from '../connected-status-bar.react.js'; -import { - addKeyboardShowListener, - addKeyboardDismissListener, - removeKeyboardListener, -} from '../keyboard/keyboard.js'; +import { useKeyboardHeight } from '../keyboard/animated-keyboard.js'; import { createIsForegroundSelector } from '../navigation/nav-selectors.js'; import { NavContext } from '../navigation/navigation-context.js'; import type { RootNavigationProp } from '../navigation/root-navigator.react.js'; @@ -53,7 +48,6 @@ import { derivedDimensionsInfoSelector } from '../selectors/dimensions-selectors.js'; import { splashStyleSelector } from '../splash.js'; import { useStyles } from '../themes/colors.js'; -import type { KeyboardEvent } from '../types/react-native.js'; import { runTiming, ratchetAlongWithKeyboardHeight, @@ -311,10 +305,23 @@ const dimensions = useSelector(derivedDimensionsInfoSelector); const contentHeight = useValue(dimensions.safeAreaHeight); - const keyboardHeightValue = useValue(0); const modeValue = useValue(modeNumbers[initialMode]); const buttonOpacity = useValue(persistedStateLoaded ? 1 : 0); + const [activeAlert, setActiveAlert] = React.useState(false); + + const navContext = React.useContext(NavContext); + const isForeground = isForegroundSelector(navContext); + + const keyboardHeightInput = React.useMemo( + () => ({ + ignoreKeyboardDismissal: activeAlert, + disabled: !isForeground, + }), + [activeAlert, isForeground], + ); + const keyboardHeightValue = useKeyboardHeight(keyboardHeightInput); + const prevModeValue = useValue(modeNumbers[initialMode]); const panelPaddingTop = React.useMemo(() => { const headerHeight = Platform.OS === 'ios' ? 62.33 : 58.54; @@ -468,52 +475,6 @@ } }, [persistedStateLoaded, combinedSetMode]); - const activeAlertRef = React.useRef(false); - const setActiveAlert = React.useCallback((activeAlert: boolean) => { - activeAlertRef.current = activeAlert; - }, []); - - const keyboardShow = React.useCallback( - (event: KeyboardEvent) => { - if ( - event.startCoordinates && - _isEqual(event.startCoordinates)(event.endCoordinates) - ) { - return; - } - const keyboardHeight: number = Platform.select({ - // Android doesn't include the bottomInset in this height measurement - android: event.endCoordinates.height, - default: Math.max( - event.endCoordinates.height - dimensions.bottomInset, - 0, - ), - }); - keyboardHeightValue.setValue(keyboardHeight); - }, - [dimensions.bottomInset, keyboardHeightValue], - ); - const keyboardHide = React.useCallback(() => { - if (!activeAlertRef.current) { - keyboardHeightValue.setValue(0); - } - }, [keyboardHeightValue]); - - const navContext = React.useContext(NavContext); - const isForeground = isForegroundSelector(navContext); - - React.useEffect(() => { - if (!isForeground) { - return undefined; - } - const keyboardShowListener = addKeyboardShowListener(keyboardShow); - const keyboardHideListener = addKeyboardDismissListener(keyboardHide); - return () => { - removeKeyboardListener(keyboardShowListener); - removeKeyboardListener(keyboardHideListener); - }; - }, [isForeground, keyboardShow, keyboardHide]); - const resetToPrompt = React.useCallback(() => { if (nextModeRef.current !== 'prompt') { goBackToPrompt(); diff --git a/native/keyboard/animated-keyboard.js b/native/keyboard/animated-keyboard.js new file mode 100644 --- /dev/null +++ b/native/keyboard/animated-keyboard.js @@ -0,0 +1,72 @@ +// @flow + +import _isEqual from 'lodash/fp/isEqual.js'; +import * as React from 'react'; +import { Platform } from 'react-native'; +import Reanimated from 'react-native-reanimated'; + +import { + addKeyboardShowListener, + addKeyboardDismissListener, + removeKeyboardListener, +} from './keyboard.js'; +import { useSelector } from '../redux/redux-utils.js'; +import { derivedDimensionsInfoSelector } from '../selectors/dimensions-selectors.js'; +import type { KeyboardEvent } from '../types/react-native.js'; + +const { useValue, Value } = Reanimated; + +type UseKeyboardHeightParams = { + +ignoreKeyboardDismissal?: ?boolean, + +disabled?: ?boolean, +}; + +function useKeyboardHeight(params?: ?UseKeyboardHeightParams): Value { + const ignoreKeyboardDismissal = params?.ignoreKeyboardDismissal; + const disabled = params?.disabled; + + const keyboardHeightValue = useValue(0); + + const dimensions = useSelector(derivedDimensionsInfoSelector); + const keyboardShow = React.useCallback( + (event: KeyboardEvent) => { + if ( + event.startCoordinates && + _isEqual(event.startCoordinates)(event.endCoordinates) + ) { + return; + } + const keyboardHeight: number = Platform.select({ + // Android doesn't include the bottomInset in this height measurement + android: event.endCoordinates.height, + default: Math.max( + event.endCoordinates.height - dimensions.bottomInset, + 0, + ), + }); + keyboardHeightValue.setValue(keyboardHeight); + }, + [dimensions.bottomInset, keyboardHeightValue], + ); + const keyboardHide = React.useCallback(() => { + if (!ignoreKeyboardDismissal) { + keyboardHeightValue.setValue(0); + } + }, [ignoreKeyboardDismissal, keyboardHeightValue]); + + React.useEffect(() => { + if (disabled) { + return undefined; + } + const keyboardShowListener = addKeyboardShowListener(keyboardShow); + const keyboardHideListener = addKeyboardDismissListener(keyboardHide); + return () => { + removeKeyboardListener(keyboardShowListener); + removeKeyboardListener(keyboardHideListener); + }; + }, [disabled, keyboardShow, keyboardHide]); + + return keyboardHeightValue; +} + +export { useKeyboardHeight };