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

[HOLD][$4000] IOS - VBA - Keyboard is overlapping the company website filed under Company Information page #9542

Closed
kbecciv opened this issue Jun 22, 2022 · 47 comments
Assignees
Labels
Bug Something is broken. Auto assigns a BugZero manager. Engineering External Added to denote the issue can be worked on by a contributor Monthly KSv2

Comments

@kbecciv
Copy link

kbecciv commented Jun 22, 2022

If you haven’t already, check out our contributing guidelines for onboarding and email [email protected] to request to join our Slack channel!


Action Performed:

  1. Login in App
  2. Go to Settings - Workspace - Connect bank account
  3. Use credentials: user_good/pass_good
  4. Select Wells Fargo and than Saving account
  5. Start to enter data into Company Information page
  6. In step 2 (company information) enter the phone number and start entering company website

Expected Result:

Keyboard is not overlapping the company website filed under Company Information page

Actual Result:

Keyboard is overlapping the company website filed under Company Information page

Workaround:

Unknow

Platform:

Where is this issue occurring?

  • iOS

Version Number: 1.1.78.7

Reproducible in staging?: Yes

Reproducible in production?: Yes

Email or phone of affected tester (no customers): any

Logs: https://stackoverflow.com/c/expensify/questions/4856

Notes/Photos/Videos: Any additional supporting documentation

Bug5619819_RPReplay_Final1655917879.mp4

Expensify/Expensify Issue URL:

Issue reported by: Applause - Internal Team

Slack conversation:

View all open jobs on GitHub

@melvin-bot
Copy link

melvin-bot bot commented Jun 22, 2022

Triggered auto assignment to @PauloGasparSv (Engineering), see https://stackoverflow.com/c/expensify/questions/4319 for more details.

@PauloGasparSv PauloGasparSv added the External Added to denote the issue can be worked on by a contributor label Jun 24, 2022
@PauloGasparSv PauloGasparSv removed their assignment Jun 24, 2022
@melvin-bot
Copy link

melvin-bot bot commented Jun 24, 2022

Triggered auto assignment to @Christinadobrzyn (External), see https://stackoverflow.com/c/expensify/questions/8582 for more details.

@Christinadobrzyn
Copy link
Contributor

I think this might be related to Accessibility - reaching out in open-source for a buddy check - https://expensify.slack.com/archives/C01GTK53T8Q/p1656108828757429

@melvin-bot melvin-bot bot added the Overdue label Jun 27, 2022
@Christinadobrzyn Christinadobrzyn changed the title IOS - VBA - Keyboard is overlapping the company website filed under Company Information page [$250] IOS - VBA - Keyboard is overlapping the company website filed under Company Information page Jun 27, 2022
@Christinadobrzyn
Copy link
Contributor

Christinadobrzyn commented Jun 27, 2022

Nope C+ confirmed this is a bug. Created Upwork job

Internal positing - https://www.upwork.com/ab/applicants/1541435223002427392/job-details
External positing - https://www.upwork.com/jobs/~01734e552bce49e505

@melvin-bot melvin-bot bot removed the Overdue label Jun 27, 2022
@melvin-bot melvin-bot bot added Weekly KSv2 and removed Daily KSv2 labels Jun 27, 2022
@melvin-bot
Copy link

melvin-bot bot commented Jun 27, 2022

Triggered auto assignment to Contributor-plus team member for initial proposal review - @mananjadhav (Exported)

@melvin-bot melvin-bot bot added the Help Wanted Apply this label when an issue is open to proposals by contributors label Jun 27, 2022
@melvin-bot
Copy link

melvin-bot bot commented Jun 27, 2022

Triggered auto assignment to @puneetlath (Exported), see https://stackoverflow.com/c/expensify/questions/7972 for more details.

@Karim-30
Copy link
Contributor

Proposal

Phone number text input opens numeric keyboard and Company website text input opens alphabetical keyboard, alphabetical keyboard is taller than numeric keyboard, so if we move Company website text input above Phone number text input we guarantee that switching from an upper text input to a lower text input will cause a keyboard shrinking.

I know it is a very simple solution, but I tried to wrap the code inside KeyboardAvoidingView component and no luck, so rather than fix out KeyboardAvoidingView component or create a new wrapper component and use it only on one page (we don't have any page has this number of input fields ), we can use this simple solution.

Result :

Screen.Recording.2022-06-28.at.5.53.34.PM.mov

@melvin-bot melvin-bot bot added Daily KSv2 and removed Weekly KSv2 labels Jun 28, 2022
@mananjadhav
Copy link
Collaborator

@Karim-30 Thank you for the comment, but your solution looks like a workaround and doesn't solve the actual problem. Looking for a proposal that probably adjusts the view on focus of the input.

@melvin-bot melvin-bot bot added the Overdue label Jul 4, 2022
@melvin-bot
Copy link

melvin-bot bot commented Jul 5, 2022

@puneetlath, @mananjadhav, @Christinadobrzyn Huh... This is 4 days overdue. Who can take care of this?

@Christinadobrzyn
Copy link
Contributor

Christinadobrzyn commented Jul 6, 2022

Looks like we're still collecting proposals for this job - price increase to $500

@melvin-bot melvin-bot bot removed the Overdue label Jul 6, 2022
@puneetlath puneetlath added Weekly KSv2 and removed Daily KSv2 labels Aug 11, 2022
@puneetlath
Copy link
Contributor

Increasing price to $4000.

@puneetlath puneetlath changed the title [$2000] IOS - VBA - Keyboard is overlapping the company website filed under Company Information page [$4000] IOS - VBA - Keyboard is overlapping the company website filed under Company Information page Aug 11, 2022
@melvin-bot melvin-bot bot added the Overdue label Aug 19, 2022
@mananjadhav
Copy link
Collaborator

@b1tjoy I went through your proposal and also explored other alternatives meanwhile, I have a question, could you please explain in which cases is the text input going out of section when used with automaticallyAdjustKeyboardInsets. If say some issue does exist with automaticallyAdjustKeyboardInsets it would make sense to fix that rather than have a workaround for us to track the scroll with keyboard events. Let me know what you think? I checked thread and the PR for automaticallyAdjustKeyboardInsets and it seems it was intended to solve this current issue only! We can explain manually tracking the scroll as a secondary option.

@melvin-bot melvin-bot bot removed the Overdue label Aug 23, 2022
@b1tjoy
Copy link
Contributor

b1tjoy commented Aug 28, 2022

@mananjadhav When I submit #9542 (comment), we use react-native 0.66.4 in our App, I backport the PR for automaticallyAdjustKeyboardInsets to react-native 0.66.4, and I found out that the text input go out of section in some case.

Our current main branch use react-native 0.69.4, I retest with automaticallyAdjustKeyboardInsets, the text input won't goes out of section, but it still cause other issue. When we use ScrollView with automaticallyAdjustKeyboardInsets, it provide keyboard avoiding feature like KeyboardAvoidingView. If we use KeyboardAvoidingView wrap around ScrollView, the scrollable area will become smaller than we expected if keyboard pop out.

Check out the following screen recording, pay attention to the scroll bar on the right hand.

iOS-native-2022-08-28-125028.mp4

If we do not use KeyboardAvoidingView wrap around ScrollView, the scrollalbe area won't get smaller, and the company website field won't blocked by keyboard. Here is a simple modification to show it really works. If we use this, the final code will be platform specific, more complex and not affect other pages and components.

  1. Disable KeyboardAvoidingView in ScreenWrapper.js

<KeyboardAvoidingView style={[styles.w100, styles.h100]} behavior={this.props.keyboardAvoidingViewBehavior}>

- <KeyboardAvoidingView style={[styles.w100, styles.h100]} behavior={this.props.keyboardAvoidingViewBehavior}>
+ <KeyboardAvoidingView enable={false} style={[styles.w100, styles.h100]} behavior={this.props.keyboardAvoidingViewBehavior}>
  1. Add automaticallyAdjustKeyboardInsets to FormScrollView.js

<ScrollView
style={[styles.w100, styles.flex1]}
ref={ref}
contentContainerStyle={styles.flexGrow1}
keyboardShouldPersistTaps="handled"

+ automaticallyAdjustKeyboardInsets

Screenshot for the modification above.

iOS-native-2022-08-28-114415.mp4

I also notice that some text input is pushed out of section first and then pulled into second, that is annoying. I will check the PR which brings automaticallyAdjustKeyboardInsets into ScrollView and find out is there anything I can do with it.

iOS-native-2022-08-28-114340.mp4

@mananjadhav
Copy link
Collaborator

I'll check your findings @b1tjoy. Thanks for the post.

@b1tjoy
Copy link
Contributor

b1tjoy commented Sep 2, 2022

Update with my findings.

1. I don't think we can use automaticallyAdjustKeyboardInsets here

After I check the PR facebook/react-native#31402 and read react-native ScrollView source code, I know what automaticallyAdjustKeyboardInsets actually do. The author of that PR add automaticallyAdjustKeyboardInsets to ScrollView to make sure the bottom area of ScrollView remain visible if keyboard pop out or resize. How he did it? By set new value to contentInset.bottom and contentOffset.y when keyboard's size change.

https://github.com/facebook/react-native/blob/4bdec975c95e8c46c804a8a00c73ebe696a6982b/React/Views/ScrollView/RCTScrollView.m#L318-L342

Here is a draft to show what automaticallyAdjustKeyboardInsets really do.

Screenshot-2022-09-02-234151

And a screenshot from the PR to show it more clearly.

after_tap.MP4

It's useful for chat App to keep bottom area of ScrollView visible when keyboard pop out. But we use ScrollView to wrap a form with multiple text fields in it. When a keyboard pop out, we prefer the top area remains visible. If we use automaticallyAdjustKeyboardInsets, the content will always scrolls up even if focused text input is not blocked by keyboard, it's not what user expected.

2. Why automaticallyAdjustKeyboardInsets works in your previous comment?

automaticallyAdjustKeyboardInsets can keep the bottom area of ScrollView visible, but in my previous #9542 (comment), I tap the top text input and the text input remains visible. Actually, it not remains visible, it's pushed out of visible area first and then dragged into visible area. You can check the video or test it very carefully.

Why the focused text input been pushed out of visible area? It's what automaticallyAdjustKeyboardInsets designed to do, keep the bottom area visible, the top area should be pushed out of visible area.

Why the focused text input been dragged into visible area later? It's a feature provide by iOS native code, text fields automatically scrolling scroll views that contain them, which means automatically scroll to get focused text field into visible area. Comment in react-native source code shows this.

https://github.com/facebook/react-native/blob/4bdec975c95e8c46c804a8a00c73ebe696a6982b/React/Views/ScrollView/RCTScrollView.m#L25-L27

And this function help to implement this feature.

https://github.com/facebook/react-native/blob/4bdec975c95e8c46c804a8a00c73ebe696a6982b/React/Views/ScrollView/RCTScrollView.m#L92-L107

If we tap a text input, the native UITextField would call RCTCustomScrollView.scrollRectToVisible, and UIScrollView.scrollRectToVisible is called in RCTCustomScrollView.scrollRectToVisible to make sure focused text input scrolls to visible area.

Screntshot-2022-09-02 8 09 49

Here is a screenshot to show native automatically scrolling feature. Notice the company website's bottom part is blocked by keyboard first, when user tap on it, the input field scrolls up automatically and become totally visible.

iOS-native-2022-09-03-122729.mp4

3. If text field can automatically scrolls to visible, why it's still blocked by keyboard in current issue? What is the root cause of our current issue?

We use KeyboardAvoidingView to wrap ScrollView in our App. When we tap a text field, there are two kinds of events, keyboardWillChangeFrame event and tap gesture event. In keyboardWillChangeFrame event handler, we get keyboard height and use it to update inner View's paddingBottom, that makes ScrollView's size and visible area change. In tap gesture handler, the native code automatically scrolls focused text input to visible area. I guess because the tap gesture event is handled by native code before keyboardWillChangeFrame event, it automatically scrolls but uses the old visible area, so the text field is still blocked by keyboard.

Check the screenshot below, notice when the keyboard change back to number at last, the company website's position changes too, which means when I tap company website field, it automatically scrolls but to old visible area.

iOS-native-2022-09-03-125819.mp4

4. Can the issue be fixed in react-native?

I don't think so. The text field automatically scrolling feature is controlled and implemented by iOS native component (UITextField and UIScrollView), it's beyond react-native's control.

5. Any other solution?

We can calculate scroll offset based on ScrollView's and TextInput's location, this solution is stable than previous one #9542 (comment).

  1. Make a new directory name FormScrollView in src/components
  2. Move src/components/FormScrollView.js to src/components/FormScrollView/index.js, fix import path error for styles
  3. Touch a new file src/components/FormScrollView/index.ios.js, and add the following code to it
import React from 'react';
import PropTypes from 'prop-types';
import {
    // eslint-disable-next-line no-restricted-imports
    InteractionManager, Keyboard, ScrollView, TextInput,
} from 'react-native';
import _ from 'underscore';
import styles from '../../styles/styles';

const propTypes = {
    /** Form elements */
    children: PropTypes.node.isRequired,

    /** A ref to forward to the scroll view */
    forwardedRef: PropTypes.func,
};

const defaultProps = {
    forwardedRef: null,
};

class FormScrollView extends React.Component {
    constructor(props) {
        super(props);
        this.keyboardHeight = 0;
        this.adjustScrollPosition = this.adjustScrollPosition.bind(this);
    }

    componentDidMount() {
        this.keyboardDidChangeFrameSubscription = Keyboard.addListener('keyboardWillChangeFrame', this.adjustScrollPosition);
    }

    componentWillUnmount() {
        this.keyboardDidChangeFrameSubscription.remove();
    }

    adjustScrollPosition(keyboardFrame) {
        const oldKeyboardHeight = this.keyboardHeight;
        this.keyboardHeight = keyboardFrame.endCoordinates.height;
        if (oldKeyboardHeight === 0 || this.keyboardHeight <= oldKeyboardHeight) {
            // Keyboard first time pop out or keyboard size does not grow, ScrollView can
            // scroll to focused TextInput automaticlly, we don't need to deal with it
            return;
        }

        const currentlyFocusedRef = TextInput.State.currentlyFocusedInput();
        if (!currentlyFocusedRef) {
            return;
        }

        currentlyFocusedRef.measureInWindow((inputX, inputY, inputWidth, inputHeight) => {
            const textInputBottomPosition = inputY + inputHeight;
            if (textInputBottomPosition <= keyboardFrame.endCoordinates.screenY) {
                return;
            }

            this.form.measure((svX, svY, svWidth, svHeight) => {
                currentlyFocusedRef.measureLayout(this.form, (left, top, width, height) => {
                    const scrollY = (top + height) - svHeight;
                    InteractionManager.runAfterInteractions(() => this.form.scrollTo({y: scrollY}));
                });
            });
        });
    }

    render() {
        return (
            <ScrollView
                style={[styles.w100, styles.flex1]}
                ref={(ref) => {
                    this.form = ref;
                    if (_.isFunction(this.props.forwardedRef)) {
                        this.props.forwardedRef(ref);
                    }
                }}
                contentContainerStyle={styles.flexGrow1}
                keyboardShouldPersistTaps="handled"
                // automaticallyAdjustKeyboardInsets
                // eslint-disable-next-line react/jsx-props-no-spreading
                {...this.props}
            >
                {this.props.children}
            </ScrollView>
        );
    }
}

FormScrollView.propTypes = propTypes;
FormScrollView.defaultProps = defaultProps;

export default React.forwardRef((props, ref) => (
    // eslint-disable-next-line react/jsx-props-no-spreading
    <FormScrollView {...props} forwardedRef={ref} />
));

Screenshot

iOS-native-2022-09-03-012103.mp4

@mananjadhav
Copy link
Collaborator

Thanks @b1tjoy for the detailed explanation. I really appreciate the effort you've put into the findings.

I agree that this can't be fixed in react-native, as I checked it myself. I am going to review your comments again and give you a final go ahead by this weekend/monday. Thank you for the patience on this one.

@mananjadhav
Copy link
Collaborator

@b1tjoy Your proposal looks good to me #9542 (comment). Any kinks can be handled in the PR review while testing.

I was a bit concerned about how reliable is this const currentlyFocusedRef = TextInput.State.currentlyFocusedInput(); But it seems it was replaced from currentlyFocusedField and does work as expected.

@puneetlath All yours.

🎀 👀 🎀 
C+ reviewed

@mallenexpensify mallenexpensify changed the title [$4000] IOS - VBA - Keyboard is overlapping the company website filed under Company Information page [HOLD][$4000] IOS - VBA - Keyboard is overlapping the company website filed under Company Information page Sep 8, 2022
@mallenexpensify mallenexpensify removed the Help Wanted Apply this label when an issue is open to proposals by contributors label Sep 8, 2022
@mallenexpensify
Copy link
Contributor

We're putting all keyboard-related issues on hold for a bit while we discuss a more holistic approach to fixing them (also this and this one).

@b1tjoy it's clear you've invested a lot of time into this issue, your proposal is extremely thorough and well-outlined. You will be compensated for your work, before disscussing the amount, we want to see if the best path forward is for you to complete the issue. If so, we'd take off hold then you'd finish then get compensated 7 days after the PR hits production, assuming no regressions. We're discussing next steps internally and will have another update on the hold timeline soon (hopefully tomorrow)

@melvin-bot

This comment was marked as off-topic.

@melvin-bot melvin-bot bot added the Overdue label Sep 13, 2022
@puneetlath puneetlath added the Monthly KSv2 label Sep 20, 2022
@melvin-bot melvin-bot bot removed the Overdue label Sep 20, 2022
@puneetlath puneetlath removed the Weekly KSv2 label Sep 20, 2022
@puneetlath puneetlath added the Bug Something is broken. Auto assigns a BugZero manager. label Oct 19, 2022
@melvin-bot melvin-bot bot added the Overdue label Oct 24, 2022
@puneetlath
Copy link
Contributor

@b1tjoy @mananjadhav we didn't end up going with the proposed solution, but we would like to pay you a partial bounty for the time put into this issue. Can you both please apply to this job?

https://www.upwork.com/jobs/~01ce8cc4db0296323e

@melvin-bot melvin-bot bot removed the Overdue label Nov 1, 2022
@mananjadhav
Copy link
Collaborator

Thanks for this @puneetlath. Applied.

@puneetlath
Copy link
Contributor

All paid, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Something is broken. Auto assigns a BugZero manager. Engineering External Added to denote the issue can be worked on by a contributor Monthly KSv2
Projects
None yet
Development

No branches or pull requests

10 participants