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 for payment 2025-01-18] [$250] iOS - Composer - Composer highlight flickers after closing attachment view #54615

Open
2 of 8 tasks
IuliiaHerets opened this issue Dec 27, 2024 · 38 comments
Assignees
Labels
Awaiting Payment Auto-added when associated PR is deployed to production Bug Something is broken. Auto assigns a BugZero manager. Engineering External Added to denote the issue can be worked on by a contributor Weekly KSv2

Comments

@IuliiaHerets
Copy link

IuliiaHerets commented Dec 27, 2024

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: 9.0.79-0
Reproducible in staging?: Yes
Reproducible in production?: No
If this was caught on HybridApp, is this reproducible on New Expensify Standalone?: Yes, reproducible on both
If this was caught during regression testing, add the test name, ID and link from TestRail: Exp
Email or phone of affected tester (no customers): applausetester+909608@applause.expensifail.com
Issue reported by: Applause Internal Team
Device used: iPhone 15 Pro Max / iOS 18.2
App Component: Chat Report View

Action Performed:

  1. Launch ND or hybrid app.
  2. Go to DM.
  3. Send an image to the DM.
  4. Go back to LHN and reopen DM (so that composer is auto-focused without keyboard opening).
  5. Tap on the image.
  6. Tap app back button.

Expected Result:

Composer highlight will be persistant.

Actual Result:

Composer is highlighted, unhighlighted and then highlighted again.

Workaround:

Unknown

Platforms:

  • Android: Standalone
  • Android: HybridApp
  • Android: mWeb Chrome
  • iOS: Standalone
  • iOS: HybridApp
  • iOS: mWeb Safari
  • MacOS: Chrome / Safari
  • MacOS: Desktop

Screenshots/Videos

Bug6702848_1735292381914.ScreenRecording_12-27-2024_17-36-29_1.mp4

View all open jobs on GitHub

Upwork Automation - Do Not Edit
  • Upwork Job URL: https://www.upwork.com/jobs/~021872607582148372045
  • Upwork Job ID: 1872607582148372045
  • Last Price Increase: 2024-12-27
  • Automatic offers:
    • shubham1206agra | Contributor | 105502719
    • ikevin127 | Contributor | 105503621
Issue OwnerCurrent Issue Owner: @sonialiap
@IuliiaHerets IuliiaHerets added DeployBlockerCash This issue or pull request should block deployment Bug Something is broken. Auto assigns a BugZero manager. labels Dec 27, 2024
Copy link

melvin-bot bot commented Dec 27, 2024

Triggered auto assignment to @Beamanator (DeployBlockerCash), see https://stackoverflowteams.com/c/expensify/questions/9980/ for more details.

Copy link

melvin-bot bot commented Dec 27, 2024

💬 A slack conversation has been started in #expensify-open-source

Copy link

melvin-bot bot commented Dec 27, 2024

Triggered auto assignment to @sonialiap (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.

@melvin-bot melvin-bot bot added the Daily KSv2 label Dec 27, 2024
@github-actions github-actions bot added Engineering Hourly KSv2 and removed Daily KSv2 labels Dec 27, 2024
Copy link
Contributor

👋 Friendly reminder that deploy blockers are time-sensitive ⏱ issues! Check out the open `StagingDeployCash` deploy checklist to see the list of PRs included in this release, then work quickly to do one of the following:

  1. Identify the pull request that introduced this issue and revert it.
  2. Find someone who can quickly fix the issue.
  3. Fix the issue yourself.

@Beamanator Beamanator added External Added to denote the issue can be worked on by a contributor Daily KSv2 and removed DeployBlockerCash This issue or pull request should block deployment Hourly KSv2 labels Dec 27, 2024
@melvin-bot melvin-bot bot changed the title iOS - Composer - Composer highlight flickers after closing attachment view [$250] iOS - Composer - Composer highlight flickers after closing attachment view Dec 27, 2024
Copy link

melvin-bot bot commented Dec 27, 2024

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

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

melvin-bot bot commented Dec 27, 2024

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

@Beamanator
Copy link
Contributor

This doesn't look big enough to be a blocker. Also I wonder if this was caused by #54189 🤔 just cuz it looks like a similar topic 😅

Though it doesn't look it necessarily affects the main composer which is what this issue is about 🤔

cc @QichenZhu @brunovjk in case y'all can take a look

@brunovjk
Copy link
Contributor

Thanks @Beamanator, I will take a look now

@Beamanator
Copy link
Contributor

Thanks!!

@brunovjk
Copy link
Contributor

@Beamanator I reverted our PR, but the issue here is still reproducible, IMO it doesn't seem related to our changes. I will continue investigating to find the root cause and a solution. Any additional insights are welcome!

@ikevin127
Copy link
Contributor

Proposal

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

Composer highlight (focus state styles) flicker after closing attachment view.

What is the root cause of that problem?

The flicher is caused by the logic implemented by PR #34404, which fixed issue #33466. The problem with the logic implemented by the PR is that in our issue's case, once we close the modal we already have logic in place to re-focus the input, but the additional logic added by the PR does that once again -> refocusing twice which causes our issue.

Details

  • in Composer/index.native.tsx the useResetComposerFocus hook is used and shouldResetFocusRef is set to true
  • that above implementation causes the useResetComposerFocus hook logic to focus input again as mentioned in the hook comment, which can be verified by commenting out this line which would fix our issue

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

The problem is that we can't simply revert the PR logic since that would reintroduce issue #33466, therefore here's what I propose in order to have both issues fixed.

We have to ensure that the useResetComposerFocus logic is only triggered when the #33466 issue steps are executed, and when our issue steps are executed -> skip useResetComposerFocus logic.

You might ask: How can we distinguish between the report details page being opened from the header while edit input is focused, then closed to allow useResetComposerFocus to execute VS the attachment modal opening while composer is focused, then closed in order to block useResetComposerFocus from executing ?

This is simple since we know that attachment modal is a modal, we can simply use the logic from ComposerWithSuggestions to detect whether a modal was previously opened:

const [modal] = useOnyx(ONYXKEYS.MODAL);
const prevIsModalVisible = usePrevious(modal?.isVisible);

using this, we modify the useResetComposerFocus hook as follows:

// new imports
import {useOnyx} from 'react-native-onyx';
import ONYXKEYS from '@src/ONYXKEYS';
import usePrevious from './usePrevious';

export default function useResetComposerFocus(inputRef: MutableRefObject<TextInput | null>) {
    const isFocused = useIsFocused();
    const shouldResetFocusRef = useRef(false);
    const [modal] = useOnyx(ONYXKEYS.MODAL); // <- add this like
    const prevIsModalVisible = usePrevious(modal?.isVisible); // <- add this like

    useEffect(() => {
        if (!isFocused || !shouldResetFocusRef.current || prevIsModalVisible) { // <- add additional OR check to return early
            return;
        }
        inputRef.current?.focus(); // focus input again
        shouldResetFocusRef.current = false;
    }, [isFocused, inputRef, prevIsModalVisible]);

    return {isFocused, shouldResetFocusRef};
}

this way we fix both issues, take a look:

iOS: Native
Our Issue The Other Issue
after-main.mp4
after-other.mp4

What specific scenarios should we cover in automated tests to prevent reintroducing this issue in the future?

N/A

Result video (before / after)

iOS: Native
Before After
before.mp4
after-main.mp4

@Beamanator If proposal makes sense, I'd like to work on this as Contributor and have somebody else step in as Reviewer, as per the C+ process doc:

If C+ wants to submit a proposal to fix the issue they do so and tag the internal engineer (by adding “ 🎀👀🎀”) to review the proposal. All other aspects of working on the issue as the same as other contributors (as of Feb 2024 this is very rare)

Copy link

melvin-bot bot commented Dec 28, 2024

Current assignee @Beamanator is eligible for the choreEngineerContributorManagement assigner, not assigning anyone new.

@huult
Copy link
Contributor

huult commented Dec 28, 2024

Proposal

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

Composer highlight flickers after closing attachment view

What is the root cause of that problem?

When I debugged this issue, I observed that it only occurs on native iOS and does not happen on native Android. Additionally, the behavior differs from the web version.

The RCA is that we call textInput focus while the transition and animation are not complete, causing the highlight to appear and then disappear again.

inputRef.current?.focus(); // focus input again

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

To resolve this issue, we just need to delay until the transition and animation are complete, then call focus, like this:

inputRef.current?.focus(); // focus input again
shouldResetFocusRef.current = false;

Add InteractionManager.runAfterInteractions when calling focus. This issue only occurs on native iOS, and we will implement it as shown below:

  1. Create InputFocusResetHandler folder in

https://github.com/Expensify/App/blob/93260a60eac6ce6200ec164fb967529db35ff071/src/libs

  • index.ts
  import type InputFocusResetHandler from './types';

  const inputFocusResetHandler: InputFocusResetHandler = {
      handleInputFocusReset: (inputRef, shouldResetFocusRef) => {
          if (!inputRef.current || !shouldResetFocusRef.current) {
              return;
          }

          inputRef?.current?.focus();
          const resetFocusRef = shouldResetFocusRef;
          resetFocusRef.current = false;
      },
  };

  export default inputFocusResetHandler;
  • index.ios.ts
  import {InteractionManager} from 'react-native';
  import type InputFocusResetHandler from './types';

  const inputFocusResetHandler: InputFocusResetHandler = {
      handleInputFocusReset: (inputRef, shouldResetFocusRef) => {
          if (!inputRef.current || !shouldResetFocusRef.current) {
              return;
          }

          InteractionManager.runAfterInteractions(() => {
              inputRef?.current?.focus();
              const resetFocusRef = shouldResetFocusRef;
              resetFocusRef.current = false;
          });
      },
  };

  export default inputFocusResetHandler;
  • types.ts
  import type {MutableRefObject} from 'react';
  import type {TextInput} from 'react-native';

  type InputFocusResetHandler = {
      handleInputFocusReset: (inputRef: MutableRefObject<TextInput | null>, shouldResetFocusRef: React.MutableRefObject<boolean>) => void;
  };

  export default InputFocusResetHandler;
  1. Update useResetComposerFocus hook to:

export default function useResetComposerFocus(inputRef: MutableRefObject<TextInput | null>) {
const isFocused = useIsFocused();
const shouldResetFocusRef = useRef(false);
useEffect(() => {
if (!isFocused || !shouldResetFocusRef.current) {
return;
}
inputRef.current?.focus(); // focus input again
shouldResetFocusRef.current = false;
}, [isFocused, inputRef]);
return {isFocused, shouldResetFocusRef};
}

export default function useResetComposerFocus(inputRef: MutableRefObject<TextInput | null>) {
    const isFocused = useIsFocused();
    const shouldResetFocusRef = useRef(false);

    useEffect(() => {
        if (!isFocused || !shouldResetFocusRef.current) {
            return;
        }

        inputFocusResetHandler.handleInputFocusReset(inputRef, shouldResetFocusRef);
    }, [isFocused, inputRef]);

    return {isFocused, shouldResetFocusRef};
}
POC
Screen.Recording.2024-12-28.at.14.26.52.mp4

Test branch

What specific scenarios should we cover in automated tests to prevent reintroducing this issue in the future?

I think we don’t need to test this because it is a UI bug.

What alternative solutions did you explore? (Optional)

Reminder: Please use plain English, be brief and avoid jargon. Feel free to use images, charts or pseudo-code if necessary. Do not post large multi-line diffs or write walls of text. Do not create PRs unless you have been hired for this job.

@brunovjk
Copy link
Contributor

brunovjk commented Dec 28, 2024

@Beamanator If proposal makes sense, I'd like to work on this as Contributor and have somebody else step in as Reviewer,

I would love to help with the review if needed.

Copy link

melvin-bot bot commented Dec 30, 2024

📣 @shubham1206agra 🎉 An offer has been automatically sent to your Upwork account for the Contributor role 🎉 Thanks for contributing to the Expensify app!

Offer link
Upwork job
Please accept the offer and leave a comment on the Github issue letting us know when we can expect a PR to be ready for review 🧑‍💻
Keep in mind: Code of Conduct | Contributing 📖

@Beamanator
Copy link
Contributor

Also @shubham1206agra can you please review @huult 's thoughts and let us know what you think? @ikevin127 i'd be curious for your opinion too if you don't mind

@shubham1206agra
Copy link
Contributor

Oh shit. I didn't see the message. You can assign @brunovjk here if you want for C+

I am really sorry for this.

@shubham1206agra
Copy link
Contributor

@shubham1206agra I see this only happens on iOS native and does not occur on Android native. This is because the focus was added later for advanced focus management when opening or closing modals. Therefore, I think delaying it is still a better solution to cover the remaining cases. What do you think?

Screen.Recording.2024-12-30.at.14.12.31.mov

Nope, I don't think time delays are a good solution.

@Beamanator
Copy link
Contributor

Oh shit. I didn't see the message. You can assign @brunovjk here if you want for C+

I am really sorry for this.

Appreciate it! I would say you just "owe @brunovjk one" or some chocolate or something like that, but y'all can figure it out 😅

@huult
Copy link
Contributor

huult commented Dec 30, 2024

Nope, I don't think time delays are a good solution.

It’s simpler than checking the modal, RHP, or LHP to return early. If we miss one or the other, this issue will happen again. Anyway, I appreciate your selection. Thanks for your feedback!

@ikevin127
Copy link
Contributor

@ikevin127 i'd be curious for your opinion too if you don't mind

@Beamanator Definitely not for adding delay in this case as that doesn't fix the issue from the root, just patches the symptom. The root being that we focus the composer twice, which we shouldn't do in the first place.

I agree with @shubham1206agra's review and comments on the other proposal.

@brunovjk
Copy link
Contributor

Oh shit. I didn't see the message. You can assign @brunovjk here if you want for C+
I am really sorry for this.

Appreciate it! I would say you just "owe @brunovjk one" or some chocolate or something like that, but y'all can figure it out 😅

Hey team, no worries on my end about the review! I’m still available to help if needed but I’m confident @shubham1206agra will do a great job as well 🚀 🚀 Thank you @Beamanator ❤️

Copy link

melvin-bot bot commented Dec 30, 2024

📣 @ikevin127 🎉 An offer has been automatically sent to your Upwork account for the Contributor role 🎉 Thanks for contributing to the Expensify app!

Offer link
Upwork job
Please accept the offer and leave a comment on the Github issue letting us know when we can expect a PR to be ready for review 🧑‍💻
Keep in mind: Code of Conduct | Contributing 📖

@Beamanator
Copy link
Contributor

Alright let's get goin' w/ @ikevin127 's proposal! Thanks all!

@ikevin127
Copy link
Contributor

Will open the PR sometime today (PST), thanks everyone!

@ikevin127
Copy link
Contributor

PR #54670 is now ready for review! 🚀

@ikevin127
Copy link
Contributor

♻️ PR is and was ready for review for 3 days, still awaiting @shubham1206agra's review.

@huult
Copy link
Contributor

huult commented Jan 8, 2025

@Beamanator Sorry, the pull request to fix this issue is already using the solution I proposed in my comment. So why was my proposal rejected by this comment, only for it to be implemented in the end?

@huult
Copy link
Contributor

huult commented Jan 8, 2025

@Beamanator I think if we changed the solution, then my proposal should be reconsidered because I suggested it first 😢

@shubham1206agra
Copy link
Contributor

@Beamanator Sorry, the pull request to fix this issue is already using the solution I proposed in my comment. So why was my proposal rejected by this comment, only for it to be implemented in the end?

@huult I know how it feels, but we are covering cases which are not defined in the issue itself, but we thought it would be a good idea to cover it rather than create a different ticket. But this case has happened a couple of times in the past, and no compensation will be provided to you since the solution was modified at a later stage.

I wish you luck, and maybe I can find another issue for you to work on.

See #54670 (comment) for more context on how we arrived at the solution.

@huult
Copy link
Contributor

huult commented Jan 8, 2025

It’s simpler than checking the modal, RHP, or LHP to return early. If we miss one or the other, this issue will happen again.

#54615 (comment) I mentioned a different case, but you still went with your selection. Hmm, I still feel it’s unfair. I think if you decided to change the solution, then you should have re-evaluated the proposals if they existed.

@melvin-bot melvin-bot bot added Weekly KSv2 Awaiting Payment Auto-added when associated PR is deployed to production and removed Weekly KSv2 labels Jan 11, 2025
@melvin-bot melvin-bot bot changed the title [$250] iOS - Composer - Composer highlight flickers after closing attachment view [HOLD for payment 2025-01-18] [$250] iOS - Composer - Composer highlight flickers after closing attachment view Jan 11, 2025
@melvin-bot melvin-bot bot removed the Reviewing Has a PR in review label Jan 11, 2025
Copy link

melvin-bot bot commented Jan 11, 2025

Reviewing label has been removed, please complete the "BugZero Checklist".

Copy link

melvin-bot bot commented Jan 11, 2025

The solution for this issue has been 🚀 deployed to production 🚀 in version 9.0.83-5 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue:

If no regressions arise, payment will be issued on 2025-01-18. 🎊

For reference, here are some details about the assignees on this issue:

Copy link

melvin-bot bot commented Jan 11, 2025

@ikevin127 / @shubham1206agra @sonialiap @ikevin127 / @shubham1206agra The PR fixing this issue has been merged! The following checklist (instructions) will need to be completed before the issue can be closed. Please copy/paste the BugZero Checklist from here into a new comment on this GH and complete it. If you have the K2 extension, you can simply click: [this button]

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

No branches or pull requests

7 participants