diff --git a/src/pages/settings/ExitSurvey/ExitSurveyResponsePage.tsx b/src/pages/settings/ExitSurvey/ExitSurveyResponsePage.tsx index 83f5d90b85af..c14c20ffc992 100644 --- a/src/pages/settings/ExitSurvey/ExitSurveyResponsePage.tsx +++ b/src/pages/settings/ExitSurvey/ExitSurveyResponsePage.tsx @@ -1,5 +1,5 @@ import type {StackScreenProps} from '@react-navigation/stack'; -import React, {useCallback, useEffect} from 'react'; +import React, {useCallback, useEffect, useState} from 'react'; import {withOnyx} from 'react-native-onyx'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; @@ -14,10 +14,13 @@ import useKeyboardState from '@hooks/useKeyboardState'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useSafeAreaInsets from '@hooks/useSafeAreaInsets'; +import useSafePaddingBottomStyle from '@hooks/useSafePaddingBottomStyle'; +import useStyledSafeAreaInsets from '@hooks/useStyledSafeAreaInsets'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import * as NumberUtils from '@libs/NumberUtils'; +import StatusBar from '@libs/StatusBar'; import updateMultilineInputRange from '@libs/updateMultilineInputRange'; import Navigation from '@navigation/Navigation'; import type {SettingsNavigatorParamList} from '@navigation/types'; @@ -43,8 +46,19 @@ function ExitSurveyResponsePage({draftResponse, route, navigation}: ExitSurveyRe const StyleUtils = useStyleUtils(); const {keyboardHeight} = useKeyboardState(); const {windowHeight} = useWindowDimensions(); - const {top: safeAreaInsetsTop} = useSafeAreaInsets(); const {inputCallbackRef, inputRef} = useAutoFocusInput(); + const [headerTitleHeight, setHeaderTitleHeight] = useState(0); + + // Device safe area top and bottom insets. + // When the keyboard is shown, the bottom inset doesn't affect the height, so we take it out from the calculation. + const {top: safeAreaInsetsTop, bottom: safeAreaInsetsBottom} = useSafeAreaInsets(); + const safeAreaInsetsBottomValue = !keyboardHeight ? safeAreaInsetsBottom : 0; + // FormWrapper bottom padding + const {paddingBottom: formPaddingBottom} = useStyledSafeAreaInsets(); + const formPaddingBottomValue = formPaddingBottom || styles.pb5.paddingBottom; + // Extra bottom padding in FormAlertWithSubmitButton + const safePaddingBottomStyle = useSafePaddingBottomStyle(); + const safePaddingBottomStyleValue = 'paddingBottom' in safePaddingBottomStyle ? (safePaddingBottomStyle.paddingBottom as number) : 0; const {reason, backTo} = route.params; const {isOffline} = useNetwork({ @@ -71,7 +85,10 @@ function ExitSurveyResponsePage({draftResponse, route, navigation}: ExitSurveyRe const textStyle = styles.headerAnonymousFooter; const baseResponseInputContainerStyle = styles.mt7; const formMaxHeight = Math.floor( - windowHeight - + // windowHeight doesn't include status bar height in Android, so we need to add it here. + // StatusBar.currentHeight is only available on Android. + windowHeight + + (StatusBar.currentHeight ?? 0) - keyboardHeight - safeAreaInsetsTop - // Minus the height of HeaderWithBackButton @@ -81,16 +98,21 @@ function ExitSurveyResponsePage({draftResponse, route, navigation}: ExitSurveyRe ); const responseInputMaxHeight = NumberUtils.roundDownToLargestMultiple( formMaxHeight - + safeAreaInsetsBottomValue - + safePaddingBottomStyleValue - + formPaddingBottomValue - // Minus the height of the text component - textStyle.lineHeight - + headerTitleHeight - // Minus the response input margins (multiplied by 2 to create the effect of margins on top and bottom). // marginBottom does not work in this case because the TextInput is in a ScrollView and will push the button beneath it out of view, // so it's maxHeight is what dictates space between it and the button. baseResponseInputContainerStyle.marginTop * 2 - // Minus the approximate size of a default button variables.componentSizeLarge - - // Minus the vertical margins around the form button - 40, + // Minus the height above the button for the form error text, accounting for 2 lines max. + variables.lineHeightNormal * 2 - + // Minus the margin between the button and the form error text + styles.mb3.marginBottom, // Round down to the largest number of full lines styles.baseTextInput.lineHeight, @@ -120,7 +142,12 @@ function ExitSurveyResponsePage({draftResponse, route, navigation}: ExitSurveyRe {isOffline && } {!isOffline && ( <> - {translate(`exitSurvey.prompts.${reason}`)} + setHeaderTitleHeight(e.nativeEvent.layout.height)} + > + {translate(`exitSurvey.prompts.${reason}`)} +