Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix the keyboard overlapping buttons on the sign in form #12848

Merged
merged 17 commits into from
Dec 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/components/FormAlertWithSubmitButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const defaultProps = {

const FormAlertWithSubmitButton = props => (
<FormAlertWrapper
containerStyles={[styles.mh5, styles.mb5, styles.flex1, styles.justifyContentEnd, ...props.containerStyles]}
containerStyles={[styles.mh5, styles.mb5, styles.justifyContentEnd, ...props.containerStyles]}
isAlertVisible={props.isAlertVisible}
isMessageHtml={props.isMessageHtml}
message={props.message}
Expand Down
7 changes: 7 additions & 0 deletions src/components/withWindowDimensions.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ const windowDimensionsPropTypes = {

// Is the window width narrow, like on a tablet device?
isMediumScreenWidth: PropTypes.bool.isRequired,

// Is the window width wide, like on a browser or desktop?
isLargeScreenWidth: PropTypes.bool.isRequired,
};

const windowDimensionsProviderPropTypes = {
Expand All @@ -35,6 +38,7 @@ class WindowDimensionsProvider extends React.Component {
const isSmallScreenWidth = initialDimensions.width <= variables.mobileResponsiveWidthBreakpoint;
const isMediumScreenWidth = initialDimensions.width > variables.mobileResponsiveWidthBreakpoint
&& initialDimensions.width <= variables.tabletResponsiveWidthBreakpoint;
const isLargeScreenWidth = !isSmallScreenWidth && !isMediumScreenWidth;

this.dimensionsEventListener = null;

Expand All @@ -43,6 +47,7 @@ class WindowDimensionsProvider extends React.Component {
windowWidth: initialDimensions.width,
isSmallScreenWidth,
isMediumScreenWidth,
isLargeScreenWidth,
};
}

Expand All @@ -67,11 +72,13 @@ class WindowDimensionsProvider extends React.Component {
const {window} = newDimensions;
const isSmallScreenWidth = window.width <= variables.mobileResponsiveWidthBreakpoint;
const isMediumScreenWidth = !isSmallScreenWidth && window.width <= variables.tabletResponsiveWidthBreakpoint;
const isLargeScreenWidth = !isSmallScreenWidth && !isMediumScreenWidth;
this.setState({
windowHeight: window.height,
windowWidth: window.width,
isSmallScreenWidth,
isMediumScreenWidth,
isLargeScreenWidth,
});
}

Expand Down
2 changes: 1 addition & 1 deletion src/pages/signin/ResendValidationForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ const ResendValidationForm = (props) => {
{!_.isEmpty(props.account.message) && (

// DotIndicatorMessage mostly expects onyxData errors so we need to mock an object so that the messages looks similar to prop.account.errors
<DotIndicatorMessage style={[styles.mb5]} type="success" messages={{0: props.account.message}} />
<DotIndicatorMessage style={[styles.mb5, styles.flex0]} type="success" messages={{0: props.account.message}} />
)}
{!_.isEmpty(props.account.errors) && (
<DotIndicatorMessage style={[styles.mb5]} type="error" messages={props.account.errors} />
Expand Down
114 changes: 49 additions & 65 deletions src/pages/signin/SignInPageLayout/SignInPageContent.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
import React from 'react';
import {ScrollView, View} from 'react-native';
import {View, TouchableWithoutFeedback, Keyboard} from 'react-native';
import PropTypes from 'prop-types';
import {withSafeAreaInsets} from 'react-native-safe-area-context';
import styles from '../../../styles/styles';
import variables from '../../../styles/variables';
import KeyboardAvoidingView from '../../../components/KeyboardAvoidingView';
import ExpensifyCashLogo from '../../../components/ExpensifyCashLogo';
import Text from '../../../components/Text';
import TermsAndLicenses from '../TermsAndLicenses';
import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
import SignInPageForm from '../../../components/SignInPageForm';
import compose from '../../../libs/compose';
import scrollViewContentContainerStyles from './signInPageStyles';
import withKeyboardState from '../../../components/withKeyboardState';
import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions';
import * as StyleUtils from '../../../styles/StyleUtils';

const propTypes = {
/** The children to show inside the layout */
Expand All @@ -31,71 +28,58 @@ const propTypes = {
...windowDimensionsPropTypes,
};

const SignInPageContent = props => (
<ScrollView
keyboardShouldPersistTaps="handled"
showsVerticalScrollIndicator={false}
style={[
styles.h100,
!props.isSmallScreenWidth && styles.alignSelfCenter,
!props.isSmallScreenWidth && styles.signInPageWideLeftContainer,
]}
contentContainerStyle={[
scrollViewContentContainerStyles,
styles.alignItemsCenter,
!props.isSmallScreenWidth && styles.ph6,
]}
>
<View style={[styles.flex1, styles.flexRow]}>
<View style={[
styles.flex1,
styles.signInPageNarrowContentContainer,
]}
>
<SignInPageForm style={[
const SignInPageContent = (props) => {
const dismissKeyboardWhenTappedOutsideOfInput = () => {
// This prop comes from withKeyboardState
if (!props.isShown) {
return;
}
Keyboard.dismiss();
};

return (
<TouchableWithoutFeedback onPress={dismissKeyboardWhenTappedOutsideOfInput}>
<View
style={[
styles.flex1,
styles.alignSelfStretch,
props.isSmallScreenWidth ? styles.ph5 : styles.ph4,
styles.signInPageLeftContainer,
!props.isSmallScreenWidth && styles.signInPageLeftContainerWide,
]}
>
<KeyboardAvoidingView
behavior="position"
style={[
StyleUtils.getModalPaddingStyles({
shouldAddBottomSafeAreaPadding: true,
modalContainerStylePaddingBottom: 20,
safeAreaPaddingBottom: props.insets.bottom,
}),
props.isSmallScreenWidth ? styles.signInPageNarrowContentMargin : {},
!props.isMediumScreenWidth || (props.isMediumScreenWidth && props.windowHeight < variables.minHeightToShowGraphics) ? styles.signInPageWideLeftContentMargin : {},
styles.mb3,
]}
>
<View style={[
styles.componentHeightLarge,
...(props.isSmallScreenWidth ? [styles.mb2] : [styles.mt6, styles.mb5]),
]}
>
<ExpensifyCashLogo
width={variables.componentSizeLarge}
height={variables.componentSizeLarge}
/>
</View>
{props.shouldShowWelcomeText && (
<Text style={[styles.mv5, styles.textLabel, styles.h3]}>
{props.welcomeText}
</Text>
)}
{props.children}
</KeyboardAvoidingView>
</SignInPageForm>
<View style={[styles.mb5, styles.alignSelfCenter, styles.ph5]}>
<TermsAndLicenses />
>
<View style={[styles.flex1, styles.alignSelfCenter, styles.signInPageWelcomeFormContainer]}>
{/* This empty view creates margin on the top of the sign in form which will shrink and grow depending on if the keyboard is open or not */}
<View style={[styles.flexGrow1, styles.signInPageContentTopSpacer]} />

<View style={[styles.flexGrow2]}>
<SignInPageForm style={[styles.alignSelfStretch]}>
<View style={[
styles.componentHeightLarge,
...(props.isSmallScreenWidth ? [styles.mb2] : [styles.mt6, styles.mb5]),
]}
>
<ExpensifyCashLogo
width={variables.componentSizeLarge}
height={variables.componentSizeLarge}
/>
</View>
{props.shouldShowWelcomeText && (
<View style={[styles.signInPageWelcomeTextContainer]}>
<Text style={[styles.mv5, styles.textLabel, styles.h3]}>
{props.welcomeText}
</Text>
</View>
)}
{props.children}
</SignInPageForm>
</View>
<View style={[styles.mv5]}>
<TermsAndLicenses />
</View>
</View>
</View>
</View>
</ScrollView>
);
</TouchableWithoutFeedback>
);
};

SignInPageContent.propTypes = propTypes;
SignInPageContent.displayName = 'SignInPageContent';
Expand Down
11 changes: 1 addition & 10 deletions src/pages/signin/SignInPageLayout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import PropTypes from 'prop-types';
import SignInPageContent from './SignInPageContent';
import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions';
import styles from '../../../styles/styles';
import variables from '../../../styles/variables';
import SignInPageGraphics from './SignInPageGraphics';

const propTypes = {
Expand All @@ -25,29 +24,21 @@ const SignInPageLayout = (props) => {
let containerStyles = [styles.flex1, styles.signInPageInner];
let contentContainerStyles = [styles.flex1, styles.flexRow];

const isLongMediumScreenWidth = props.isMediumScreenWidth && props.windowHeight >= variables.minHeightToShowGraphics;

if (props.isSmallScreenWidth) {
containerStyles = [styles.flex1];
contentContainerStyles = [styles.flex1];
} else if (isLongMediumScreenWidth) {
containerStyles = [styles.dFlex, styles.signInPageInner, styles.flexColumnReverse, styles.justifyContentBetween];
contentContainerStyles = [styles.flex1];
}

return (
<View style={containerStyles}>
{isLongMediumScreenWidth && (
<SignInPageGraphics />
)}
<View style={contentContainerStyles}>
<SignInPageContent
welcomeText={props.welcomeText}
shouldShowWelcomeText={props.shouldShowWelcomeText}
>
{props.children}
</SignInPageContent>
{!props.isSmallScreenWidth && !isLongMediumScreenWidth && (
{!props.isSmallScreenWidth && (
<SignInPageGraphics />
)}
</View>
Expand Down
51 changes: 12 additions & 39 deletions src/styles/styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -893,60 +893,33 @@ const styles = {
flex: 1,
},

signInPageLogo: {
height: variables.componentSizeLarge,
marginBottom: 24,
},

signInPageInner: {
marginLeft: 'auto',
marginRight: 'auto',
height: '100%',
width: '100%',
},

signInPageInnerNative: {
width: '100%',
},

signInPageHeroHeading: {
fontFamily: fontFamily.EXP_NEUE,
fontWeight: fontWeightBold,
fontSize: variables.fontSizeHero,
color: themeColors.appBG,
lineHeight: variables.lineHeightHero,
},

signInPageHeroDescription: {
fontFamily: fontFamily.EXP_NEUE,
fontSize: variables.fontSizeNormal,
color: themeColors.appBG,
},

signInPageFormContainer: {
maxWidth: 295,
width: '100%',
},

signInPageNarrowContentContainer: {
maxWidth: 335,
signInPageContentTopSpacer: {
maxHeight: 132,
minHeight: 24,
},

signInPageNarrowContentMargin: {
marginTop: '40%',
signInPageLeftContainer: {
paddingLeft: 40,
paddingRight: 40,
},

signInPageWideLeftContainer: {
width: 375,
maxWidth: 375,
signInPageLeftContainerWide: {
maxWidth: 360,
},

signInPageWideLeftContentMargin: {
marginTop: '44.5%',
signInPageWelcomeFormContainer: {
maxWidth: 300,
},

signInPageWideHeroContent: {
maxWidth: 400,
signInPageWelcomeTextContainer: {
width: 300,
},

changeExpensifyLoginLinkContainer: {
Expand Down
8 changes: 4 additions & 4 deletions src/styles/utilities/flex.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,6 @@ export default {
flexDirection: 'column',
},

flexColumnReverse: {
flexDirection: 'column-reverse',
},

justifyContentCenter: {
justifyContent: 'center',
},
Expand Down Expand Up @@ -108,6 +104,10 @@ export default {
flexGrow: 1,
},

flexGrow2: {
flexGrow: 2,
},

flexGrow4: {
flexGrow: 4,
},
Expand Down
1 change: 0 additions & 1 deletion src/styles/variables.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ export default {
tooltipzIndex: 10050,
gutterWidth: 16,
popoverMenuShadow: '0px 4px 12px 0px rgba(0, 0, 0, 0.06)',
minHeightToShowGraphics: 854, // Login form layout breaks below this height due to insufficient space to show the form and graphics
optionRowHeight: 64,
optionRowHeightCompact: 52,
optionsListSectionHeaderHeight: 54,
Expand Down