Skip to content

Commit

Permalink
ChatScreen: Fix blank strip between compose box and keyboard on iOS
Browse files Browse the repository at this point in the history
Fixes: #3370
  • Loading branch information
chrisbobbe committed Nov 21, 2022
1 parent 3fa18f3 commit 9ed6fd3
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 5 deletions.
10 changes: 9 additions & 1 deletion src/chat/ChatScreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import React, { useCallback, useContext } from 'react';
import type { Node } from 'react';
import { useIsFocused } from '@react-navigation/native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';

import { useSelector, useDispatch } from '../react-redux';
import type { RouteProp } from '../react-navigation';
Expand Down Expand Up @@ -196,7 +197,14 @@ export default function ChatScreen(props: Props): Node {
);

return (
<KeyboardAvoider style={[componentStyles.screen, { backgroundColor }]} behavior="padding">
<KeyboardAvoider
style={[componentStyles.screen, { backgroundColor }]}
behavior="padding"
compensateOverpadding={
// We let the compose box pad the bottom inset.
showComposeBox
}
>
<ChatNavBar narrow={narrow} editMessage={editMessage} />
<UnreadNotice narrow={narrow} />
{(() => {
Expand Down
38 changes: 34 additions & 4 deletions src/common/KeyboardAvoider.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React from 'react';
import type { Node } from 'react';
import { Platform, View } from 'react-native';
import type { ViewStyleProp } from 'react-native/Libraries/StyleSheet/StyleSheet';
import { useSafeAreaInsets } from 'react-native-safe-area-context';

import KeyboardAvoidingView from '../third/react-native/KeyboardAvoidingView';

Expand All @@ -12,8 +13,9 @@ type Props = $ReadOnly<{|
style?: ViewStyleProp,
contentContainerStyle?: ViewStyleProp,

/** How much the top of `KeyboardAvoider`'s layout *parent* is
* displaced downward from the top of the screen.
/**
* How much the top of `KeyboardAvoider`'s layout *parent* is
* displaced downward from the top of the screen.
*
* If this isn't set correctly, the keyboard will hide some of
* the bottom of the screen (an area whose height is what this
Expand All @@ -30,6 +32,19 @@ type Props = $ReadOnly<{|
* we can use to balance the equation if we need to.
*/
keyboardVerticalOffset?: number,

/**
* Whether to shorten the excursion by the height of the bottom inset.
*
* Use this when a child component uses SafeAreaView to pad the bottom
* inset, and you want the open keyboard to cover that padding.
*
* (SafeAreaView has a bug where it applies a constant padding no matter
* where it's positioned onscreen -- so in particular, if you ask for
* bottom padding, you'll get bottom padding even when KeyboardAvoider
* pushes the SafeAreaView up and out of the bottom inset.)
*/
compensateOverpadding?: boolean,
|}>;

/**
Expand All @@ -40,7 +55,16 @@ type Props = $ReadOnly<{|
* to that component.
*/
export default function KeyboardAvoider(props: Props): Node {
const { behavior, children, style, contentContainerStyle, keyboardVerticalOffset } = props;
const {
behavior,
children,
style,
contentContainerStyle,
keyboardVerticalOffset = 0, // Same default value as KeyboardAvoidingView
compensateOverpadding = false,
} = props;

const bottomInsetHeight = useSafeAreaInsets().bottom;

if (Platform.OS === 'android') {
return <View style={style}>{children}</View>;
Expand All @@ -51,7 +75,13 @@ export default function KeyboardAvoider(props: Props): Node {
behavior={behavior}
contentContainerStyle={contentContainerStyle}
// See comment on this prop in the jsdoc.
keyboardVerticalOffset={keyboardVerticalOffset}
keyboardVerticalOffset={
keyboardVerticalOffset
// A negative term here reduces the bottom inset we use for the
// child, when the keyboard is open, so that the keyboard covers its
// bottom padding.
+ (compensateOverpadding ? -bottomInsetHeight : 0)
}
style={style}
>
{children}
Expand Down
2 changes: 2 additions & 0 deletions src/compose/ComposeBox.js
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,8 @@ export default function ComposeBox(props: Props): Node {
</View>
<SafeAreaView
mode="padding"
// When the keyboard is open, this bottom padding is compensated
// for: we pass KeyboardAvoider's compensateOverpadding prop.
edges={['bottom']}
style={styles.composeBox}
onLayout={handleLayoutChange}
Expand Down

0 comments on commit 9ed6fd3

Please sign in to comment.