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

Mobile: Fixes #6682: Disable KeyboardAvoidingView when floating keyboard is visible #7593

3 changes: 3 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -1002,6 +1002,9 @@ packages/app-mobile/components/SelectDateTimeDialog.js.map
packages/app-mobile/components/SideMenu.d.ts
packages/app-mobile/components/SideMenu.js
packages/app-mobile/components/SideMenu.js.map
packages/app-mobile/components/app-nav.d.ts
packages/app-mobile/components/app-nav.js
packages/app-mobile/components/app-nav.js.map
packages/app-mobile/components/TextInput.d.ts
packages/app-mobile/components/TextInput.js
packages/app-mobile/components/TextInput.js.map
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -990,6 +990,9 @@ packages/app-mobile/components/SelectDateTimeDialog.js.map
packages/app-mobile/components/SideMenu.d.ts
packages/app-mobile/components/SideMenu.js
packages/app-mobile/components/SideMenu.js.map
packages/app-mobile/components/app-nav.d.ts
packages/app-mobile/components/app-nav.js
packages/app-mobile/components/app-nav.js.map
packages/app-mobile/components/TextInput.d.ts
packages/app-mobile/components/TextInput.js
packages/app-mobile/components/TextInput.js.map
Expand Down
Original file line number Diff line number Diff line change
@@ -1,32 +1,56 @@
const React = require('react');
const Component = React.Component;
const { connect } = require('react-redux');
import * as React from 'react';
import { connect } from 'react-redux';
const { NotesScreen } = require('./screens/notes.js');
const { SearchScreen } = require('./screens/search.js');
const { KeyboardAvoidingView, Keyboard, Platform, View } = require('react-native');
import { Component } from 'react';
import { KeyboardAvoidingView, Keyboard, Platform, View, KeyboardEvent, Dimensions, EmitterSubscription } from 'react-native';
import { AppState } from '../utils/types';
const { themeStyle } = require('./global-style.js');

class AppNavComponent extends Component {
constructor() {
super();
interface State {
autoCompletionBarExtraHeight: number;
floatingKeyboardEnabled: boolean;
}

interface Props {
route: any;
screens: any;
dispatch: (action: any)=> void;
themeId: number;
}

class AppNavComponent extends Component<Props, State> {
private previousRouteName_: string|null = null;
private keyboardDidShowListener: EmitterSubscription|null = null;
private keyboardDidHideListener: EmitterSubscription|null = null;
private keyboardWillChangeFrameListener: EmitterSubscription|null = null;

constructor(props: Props) {
super(props);

this.previousRouteName_ = null;
this.state = {
autoCompletionBarExtraHeight: 0, // Extra padding for the auto completion bar at the top of the keyboard
floatingKeyboardEnabled: false,
};
}

UNSAFE_componentWillMount() {
if (Platform.OS === 'ios') {
this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this.keyboardDidShow.bind(this));
this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this.keyboardDidHide.bind(this));
this.keyboardWillChangeFrameListener = Keyboard.addListener('keyboardWillChangeFrame', this.keyboardWillChangeFrame);
}
}

componentWillUnmount() {
if (this.keyboardDidShowListener) this.keyboardDidShowListener.remove();
if (this.keyboardDidHideListener) this.keyboardDidHideListener.remove();
this.keyboardDidShowListener?.remove();
this.keyboardDidHideListener?.remove();
this.keyboardWillChangeFrameListener?.remove();

this.keyboardDidShowListener = null;
this.keyboardDidHideListener = null;
this.keyboardWillChangeFrameListener = null;
}

keyboardDidShow() {
Expand All @@ -37,6 +61,16 @@ class AppNavComponent extends Component {
this.setState({ autoCompletionBarExtraHeight: 0 });
}

keyboardWillChangeFrame = (evt: KeyboardEvent) => {
const windowWidth = Dimensions.get('window').width;

// If the keyboard isn't as wide as the window, the floating keyboard is diabled.
// See https://github.com/facebook/react-native/issues/29473#issuecomment-696658937
this.setState({
floatingKeyboardEnabled: evt.endCoordinates.width < windowWidth,
});
};

render() {
if (!this.props.route) throw new Error('Route must not be null');

Expand Down Expand Up @@ -67,8 +101,17 @@ class AppNavComponent extends Component {

const style = { flex: 1, backgroundColor: theme.backgroundColor };

// When the floating keybaord is enabled, the KeyboardAvoidingView can have a very small
// height. Don't use the KeyboardAvoidingView when the floating keyboard is enabled.
// See https://github.com/facebook/react-native/issues/29473
const keyboardAvoidingViewEnabled = !this.state.floatingKeyboardEnabled;

return (
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : null} style={style}>
<KeyboardAvoidingView
enabled={keyboardAvoidingViewEnabled}
behavior={Platform.OS === 'ios' ? 'padding' : null}
style={style}
>
<NotesScreen visible={notesScreenVisible} navigation={{ state: route }} />
{searchScreenLoaded && <SearchScreen visible={searchScreenVisible} navigation={{ state: route }} />}
{!notesScreenVisible && !searchScreenVisible && <Screen navigation={{ state: route }} themeId={this.props.themeId} dispatch={this.props.dispatch} />}
Expand All @@ -78,7 +121,7 @@ class AppNavComponent extends Component {
}
}

const AppNav = connect(state => {
const AppNav = connect((state: AppState) => {
return {
route: state.route,
themeId: state.settings.theme,
Expand Down