Expensify / App

Welcome to New Expensify: a complete re-imagination of financial collaboration, centered around chat. Help us build the next generation of Expensify by sharing feedback and contributing to the code.
https://new.expensify.com
MIT License
3.14k stars 2.64k forks source link

[HOLD on #40548] [$250] iOS - Send button is not responsive after returning from transaction thread #41528

Open m-natarajan opened 2 months ago

m-natarajan commented 2 months ago

If you haven’t already, check out our contributing guidelines for onboarding and email contributors@expensify.com to request to join our Slack channel!


Version Number: 1.4.70-0 Reproducible in staging?: y Reproducible in production?: y If this was caught during regression testing, add the test name, ID and link from TestRail: n/a Email or phone of affected tester (no customers): Logs: https://stackoverflow.com/c/expensify/questions/4856 Expensify/Expensify Issue URL: Issue reported by: applause internal team Slack conversation:

Action Performed:

  1. Launch New Expensify app.
  2. Submit two expenses to a user.
  3. In 1:1 DM. tap on the expense preview twice to go to transaction thread.
  4. Tap on the back button twice to return to main chat.
  5. Type in the composer.
  6. Tap on the send button.

Expected Result:

The message is sent.

Actual Result:

The send button is not responsive.

Workaround:

unknown

Platforms:

Which of our officially supported platforms is this issue occurring on?

Screenshots/Videos

Add any screenshot/video evidence

https://github.com/Expensify/App/assets/38435837/477b0ecb-6590-4b37-83ff-48170f9712e4

View all open jobs on GitHub

Upwork Automation - Do Not Edit
  • Upwork Job URL: https://www.upwork.com/jobs/~014d8f21d1c3cead99
  • Upwork Job ID: 1787886299262738432
  • Last Price Increase: 2024-05-14
Issue OwnerCurrent Issue Owner: @garrettmknight
melvin-bot[bot] commented 2 months ago

Triggered auto assignment to @garrettmknight (Bug), see https://stackoverflow.com/c/expensify/questions/14418 for more details. Please add this bug to a GH project, as outlined in the SO.

m-natarajan commented 2 months ago

@garrettmknight FYI I haven't added the External label as I wasn't 100% sure about this issue. Please take a look and add the label if you agree it's a bug and can be handled by external contributors

m-natarajan commented 2 months ago

We think that this bug might be related to #vip-vsb

melvin-bot[bot] commented 2 months ago

Triggered auto assignment to @stephanieelliott (Bug), see https://stackoverflow.com/c/expensify/questions/14418 for more details. Please add this bug to a GH project, as outlined in the SO.

garrettmknight commented 2 months ago

@stephanieelliott wasn't sure if this was internal/external, but I'm gonna be off till Thurs. Can you repro and open it up? I'll pick it up when I get back, thanks!

melvin-bot[bot] commented 2 months ago

@garrettmknight, @stephanieelliott Whoops! This issue is 2 days overdue. Let's get this updated quick!

stephanieelliott commented 2 months ago

Site was down most of Monday so just now got the opportunity to test, and I was able to repro this. Pretty sure this can be worked on externally, adding labels to get some proposals!

melvin-bot[bot] commented 2 months ago

Job added to Upwork: https://www.upwork.com/jobs/~014d8f21d1c3cead99

melvin-bot[bot] commented 2 months ago

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

garrettmknight commented 2 months ago

Waiting for proposals.

garrettmknight commented 2 months ago

Still waiting for proposals.

melvin-bot[bot] commented 2 months ago

📣 It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? 💸

rezkiy37 commented 2 months ago

Hi, I’m Michael (Mykhailo) from Callstack and I would like to work on this issue.

melvin-bot[bot] commented 2 months ago

@garrettmknight @eVoloshchak this issue was created 2 weeks ago. Are we close to approving a proposal? If not, what's blocking us from getting this issue assigned? Don't hesitate to create a thread in #expensify-open-source to align faster in real time. Thanks!

melvin-bot[bot] commented 2 months ago

@garrettmknight, @eVoloshchak Whoops! This issue is 2 days overdue. Let's get this updated quick!

garrettmknight commented 2 months ago

Just reproduced - @rezkiy37 if you want to work on this one please put forward a root cause analysis/proposal. Thanks!

rezkiy37 commented 2 months ago

Yes, I am actively working on the issue.

rezkiy37 commented 2 months ago

I've found a solution how to fix it. I need to test performance and measure it. Also, I still don't understand the root cause. Work in progress.

rezkiy37 commented 2 months ago

After my investigations, I faced a problem with react-native-gesture-handler itself. In a few words, the problem is with GestureDetector in SendButton.tsx. I've created an issue (https://github.com/software-mansion/react-native-gesture-handler/issues/2920) for them.

Meanwhile, I see that the current flow is tricky to handle a press on the send button. I am preparing a proposal to simplify the current behavior and fix the bug immediately. So we don't need to wait until they fix react-native-gesture-handler.

melvin-bot[bot] commented 1 month ago

@garrettmknight, @eVoloshchak Whoops! This issue is 2 days overdue. Let's get this updated quick!

rezkiy37 commented 1 month ago

I've sent a proposal for the internal review.

garrettmknight commented 1 month ago

@rezkiy37 where's that proposal so I can follow along?

rezkiy37 commented 1 month ago

Proposal

Please re-state the problem that we are trying to solve in this issue.

The send button is not responsive after returning from a thread.

What is the root cause of that problem?

Currently, the app handles send button presses via GestureDetecor from react-native-gesture-handler. It allows running a handle function as a worklet from react-native-reanimated.

https://github.com/Expensify/App/blob/e8ae3c5acedf0e6788dc574c7b6f3043ca37092a/src/pages/home/report/ReportActionCompose/SendButton.tsx#L26-L28

The problem with GestureDetecor. It does not react to tap actions, when the user goes to thread (nested) screens and returns to the main report. The React DOM still has the component and Tap gesture. The configs are correct. Something happens under the hood of the third-party package.

When I tried to force update GestureDetecor via setting a new key on each screen focus, it started to work.

Details

Screenshot 2024-05-20 at 16 32 24

So it is a problem with react-native-gesture-handler. I created an issue for them - https://github.com/software-mansion/react-native-gesture-handler/issues/2920.

Meanwhile, I realized that the bug can be fixed if we improve our codebase.

What changes do you think we should make in order to solve the problem?

The basic idea of a worklet is to run code on the UI (main) thread.

https://github.com/Expensify/App/blob/e8ae3c5acedf0e6788dc574c7b6f3043ca37092a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx#L360-L372

As we can see above, this worklet runs 4 functions. However, 3 of them and it delegates back to the JS thread. So it looks strange from the thread’s perspective.

The component already uses PressableWithFeedback. So it has onPress. Definitely, onPress does not allow to run worklets. However, we don’t need it anymore. I mentioned before that only 1 function needs to be launched on the UI thread.

I propose to use onPress to call handleSendMessage. Right after that, we can simplify the function and remove worklet and runOnJS calls. Then we can use runOnUI only for setNativeProps.

const handleSendMessage = useCallback(() => {
    if (isSendDisabled || !isReportReadyForDisplay) {
        return;
    }

    // We are setting the isCommentEmpty flag to true so the status of it will be in sync of the native text input state
    setIsCommentEmpty(true);
    resetFullComposerSize();
    // Run the callback on the UI thread
    runOnUI(setNativeProps)(animatedRef, {text: ‘’}); // clears native text input on the UI thread
    submitForm();
}, [isSendDisabled, resetFullComposerSize, submitForm, animatedRef, isReportReadyForDisplay]);

This approach does work properly. Also, it does not play ping-pong between threads. It begins on the JS thread, executes JS tasks here, and requires running only this one setNativeProps on the UI thread.

What alternative solutions did you explore? (Optional)

  1. Waiting until SWM fixes https://github.com/software-mansion/react-native-gesture-handler/issues/2920.
rezkiy37 commented 1 month ago

@rezkiy37 where's that proposal so I can follow along?

Just posted above.

garrettmknight commented 1 month ago

Awesome, thanks!

@eVoloshchak mind reviewing when you've got a chance?

j-piasecki commented 1 month ago

As we can see above, this worklet runs 4 functions. However, 3 of them and it delegates back to the JS thread. So it looks strange from the thread’s perspective.

The component already uses PressableWithFeedback. So it has onPress. Definitely, onPress does not allow to run worklets. However, we don’t need it anymore. I mentioned before that only 1 function needs to be launched on the UI thread.

I propose to use onPress to call handleSendMessage. Right after that, we can simplify the function and remove worklet and runOnJS calls. Then we can use runOnUI only for setNativeProps.

It was originally done in a similar way (without runOnUI bit) but it was causing an issue where a message would stay in the compose after being sent - https://github.com/Expensify/App/pull/22227.

I believe that the proposal is to effectively restore the previous behavior. The important bit in the current implementation is not that the text is cleared on the UI thread, but it's cleared synchronously on the UI thread, skipping the JS thread entirely.

Using runOnUI would nullify that, as it would schedule the call to clear the composer asynchronously from JS thread to UI thread.

As for the fix inside RNGH, I've got an idea for how to fix this, but from my early tests, it doesn't work on RN 0.73 (which is currently used in the App). I'll try to find whether something can be backported from 0.74 to make it work, but I cannot promise anything there, so it may turn out to be necessary to wait for https://github.com/Expensify/App/pull/40548.

If you need it fixed quickly, patching out this part inside the core of RN will get rid of the problem, but may negatively impact performance since suspended views will still be mounted on the native side.

rezkiy37 commented 1 month ago

Alright, thank you! So I can try to test with RN 0.74. Also, there is a confirmation from RNGH team that the bug is replicated on their side.

If you need it fixed quickly, patching out this part inside the core of RN will get rid of the problem, but may negatively impact...

As I see it is a part for Android only.

rezkiy37 commented 1 month ago

Btw, regarding the initial bug that was fixed https://github.com/Expensify/App/pull/22227. I would like to test if it is still works properly with my proposal.

j-piasecki commented 1 month ago

As I see it is a part for Android only.

It's behind #ifndef ANDROID (if not defined) so it's for everything but Android.

rezkiy37 commented 1 month ago

As I see it is a part for Android only.

It's behind #ifndef ANDROID (if not defined) so it's for everything but Android.

Ah, my C++ knowledge leaves much to be desired 🙂

melvin-bot[bot] commented 1 month ago

@garrettmknight, @eVoloshchak, @rezkiy37 Whoops! This issue is 2 days overdue. Let's get this updated quick!

garrettmknight commented 1 month ago

@eVoloshchak bump on the review, please.

rezkiy37 commented 1 month ago

There is a PR (https://github.com/software-mansion/react-native-gesture-handler/pull/2925) where they have fixed the bug on the RNGH side. I am going to test it.

Note that this will only fix the issue on RN 0.74, since useLayoutEffect is broken on versions below that.

Seems like we need to wait for this PR to bump the RN version - https://github.com/Expensify/App/pull/40548.

eVoloshchak commented 1 month ago

@rezkiy37, this does introduce the bug from https://github.com/Expensify/App/issues/10148 back

https://github.com/Expensify/App/assets/9059945/072deaa9-c9f7-45ce-ad16-b26d6d9bac97

rezkiy37 commented 1 month ago

Okay, so I will consider another solution.

melvin-bot[bot] commented 1 month ago

@garrettmknight @eVoloshchak @rezkiy37 this issue is now 4 weeks old, please consider:

Thanks!

garrettmknight commented 1 month ago

Awaiting another proposal.

rezkiy37 commented 1 month ago

I tried https://github.com/Expensify/App/pull/40548 and https://github.com/software-mansion/react-native-gesture-handler/pull/2925 together. Unfortunately, these fixes haven't solved the current problem.

rezkiy37 commented 1 month ago

@rezkiy37, this does introduce the bug from #10148 back

RPReplay_Final1716974607.MP4

@eVoloshchak, can you try to with the next change where setNativeProps is being called first:

if (isSendDisabled || !isReportReadyForDisplay) {
    return;
}
// Run before others
runOnUI(setNativeProps)(animatedRef, {text: ''}); // clears native text input on the UI thread
// We are setting the isCommentEmpty flag to true so the status of it will be in sync of the native text input state
setIsCommentEmpty(true);
resetFullComposerSize();
submitForm();

I've tried and looks like it works properly on my side.

garrettmknight commented 1 month ago

@eVoloshchak mind giving this a look?

eVoloshchak commented 1 month ago

@rezkiy37, it's harder to reproduce, but still reproducible if you click 'Send' fast enough

https://github.com/Expensify/App/assets/9059945/898a6f56-a797-4ac9-8e1c-76b88c19c784

rezkiy37 commented 1 month ago

Okay, so I would like to wait until https://github.com/Expensify/App/pull/40548 is merged. Hopefully, the RN upgrade and RNGH fix can help us.

garrettmknight commented 1 month ago

@eVoloshchak do you agree? I can put this on hold if so.

eVoloshchak commented 1 month ago

@garrettmknight, agree, let's hold for https://github.com/Expensify/App/pull/40548

garrettmknight commented 1 month ago

Dropping to weekly while we hold.

garrettmknight commented 1 month ago

Still on hold for https://github.com/Expensify/App/pull/40548

garrettmknight commented 3 weeks ago

Still on hold for https://github.com/Expensify/App/pull/40548

garrettmknight commented 1 week ago

Still on hold for https://github.com/Expensify/App/pull/40548

rezkiy37 commented 1 week ago

Hello! FYI: I have a vacation from 11.07 to 26.07. Meanwhile, someone from Callstack can help with this issue.

garrettmknight commented 6 days ago

Still on hold for https://github.com/Expensify/App/pull/40548