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

Fix cursor moving back and missing characters #2537

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

MJ1998
Copy link
Collaborator

@MJ1998 MJ1998 commented May 8, 2024

IMPORTANT: All PRs must be linked to an issue (except for extremely trivial and straightforward changes).

Fixes #1914

Cause of the issue: The EditText temporarily contains an extra character. The TextWatcher gets removed (here) before it can process this extra character, leaving the saved text state (in QuestionnaireViewItem) inconsistent with the actual EditText content. This inconsistency triggers a UI update using EditText#setText (here), which unintentionally resets the cursor position to the beginning.

EditText#append moves the cursor to the last position.

Read comments in rest of the PR for more details.

Description
Clear and concise code change description.

Alternative(s) considered
Have you considered any alternatives? And if so, why have you chosen the approach in this PR?

Type
Choose one: (Bug fix | Feature | Documentation | Testing | Code health | Builds | Releases | Other)

Screenshots (if applicable)

Checklist

  • I have read and acknowledged the Code of conduct.
  • I have read the Contributing page.
  • I have signed the Google Individual CLA, or I am covered by my company's Corporate CLA.
  • I have discussed my proposed solution with code owners in the linked issue(s) and we have agreed upon the general approach.
  • I have run ./gradlew spotlessApply and ./gradlew spotlessCheck to check my code follows the style guide of this project.
  • I have run ./gradlew check and ./gradlew connectedCheck to test my changes locally.
  • I have built and run the demo app(s) to verify my change fixes the issue and/or does not break the demo app(s).

@MJ1998 MJ1998 requested review from santosh-pingle and a team as code owners May 8, 2024 09:29
@MJ1998 MJ1998 requested a review from yigit May 8, 2024 09:29
@MJ1998
Copy link
Collaborator Author

MJ1998 commented May 8, 2024

This, however, has a side effect (which existed earlier as well but was overlooked because of cursor resetting) of missing some characters when typing too fast.
Reason: EditText's extra character is skipped when using the above solution.

Solving this will require more effort. I can think of a solution which will involve detecting "user has stopped typing". Something like this - stackoverflow.

Let me know if you want to fix this as well. Will raise a separate issue for this.

Alternative: Use RxBindings or do some backpressure solutioning to handle all character inputs from user. But this will need a more complex handling - like "not updating the EditText until upstream processing (handleInput) is complete".

@pld
Copy link
Collaborator

pld commented May 8, 2024

@jingtang10 what are your thoughts on this?

@MJ1998
Copy link
Collaborator Author

MJ1998 commented May 8, 2024

I made an attempt at solving the "side effect" as well. Seems good to me but Idk if this behaviour - "detect user has stopped typing" can have any other side effects.

Only difficulty is to test this as racing conditions are always a pain to test.
How I tested it - Ran my finger over "QWERTY" tabs on keyboard back and forth really fast. Before the last commit I could see some missed characters. After the last commit, I didn't see any missed character in quite some attempts trying this test.

Can you try testing this PR ?
@pld

@AngelaKabari
Copy link

Thanks for all your work on this @MJ1998. @FikriMilano will test the PR tomorrow and we'll get back to you.

Copy link
Collaborator

@FikriMilano FikriMilano left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @MJ1998, I like your first idea and it's working, in a nutshell -> only apply new answer to questionnaireViewItem after user stops typing for 0.5 second, if there are more inputs coming in, the answer won't be applied since the timer is canceled.

Not sure if it's worth it to introduce RxBinding right now.

override fun afterTextChanged(editable: Editable?) {
        timer?.cancel()
        // If editable has become empty or this is the first character then invoke afterTextChanged
        // instantly else start a timer for user to finish typing
        if (editable?.toString().isNullOrEmpty() || firstCharacter) {
          Log.d("FIKRI1", "$editable")
          afterTextChanged(editable?.toString())
        } else {
          // countDownInterval is simply kept greater than delay as we don't need onTick
          timer =
            object : CountDownTimer(delay, delay * 2) {
                override fun onTick(millisUntilFinished: Long) {}

                override fun onFinish() {
                  Log.d("FIKRI2", "$editable")
                  afterTextChanged(editable?.toString())
                }
              }
              .start()
        }
      }
2024-05-09 11:24:26.372  2316-2316  FIKRI1                  com.google.android.fhir.catalog      D  
2024-05-09 11:24:27.912  2316-2316  FIKRI1                  com.google.android.fhir.catalog      D  a
2024-05-09 11:24:30.037  2316-2316  FIKRI2                  com.google.android.fhir.catalog      D  aa
2024-05-09 11:24:35.997  2316-2316  FIKRI2                  com.google.android.fhir.catalog      D  aaqwertqwertqwertqwertqwert
qwerty.webm

@MJ1998
Copy link
Collaborator Author

MJ1998 commented May 9, 2024

Just FYI an elaboration on how I am testing this:-
I slide my finger and keep it pressed over "QWERTY" keys back and forth. So the input I generate is "qwertytrewqwertytrewq...".

You can observe some characters being missed before the last commit if you test like this. @FikriMilano

In actual case the upstream function can take more time to finish (for example, resolving fhir query) - which makes characters missing clearly visible.

@MJ1998 MJ1998 changed the title Avoid EditText#setText to mitigate TextWatcher racing condition Fix cursor moving back and missing characters May 9, 2024
@MJ1998
Copy link
Collaborator Author

MJ1998 commented May 9, 2024

Regarding your question on RxBinding, I think its a much bigger effort as we dont use simple TextView or EditText views, rather its a EditTextInputLayout which offers more features like validation, header views along with it.

So moving from EditTextInputLayout to RxBinding views will be difficult.
@FikriMilano

@FikriMilano
Copy link
Collaborator

@MJ1998 I agree, we can keep it this way for now

@AngelaKabari
Copy link

@MJ1998 this fix you shared is working great. Thank you for prioritising this and getting it resolved so quickly!

@AngelaKabari
Copy link

@MJ1998 upon further testing, the issue of the missing characters is significantly affecting the data entry.

Missing.letters.bug.webm

Can we please go back to the drawing board on this?

@MJ1998
Copy link
Collaborator Author

MJ1998 commented May 17, 2024

Is this issue happening on this PR?

@AngelaKabari
Copy link

@MJ1998 yes it is.

@MJ1998
Copy link
Collaborator Author

MJ1998 commented May 21, 2024

Gotcha. I had a feeling this will introduce more side effects.
Can you tell me if there is any expression in your questionnaire's items that are dependent (directly or indirectly) on this item being modified ?

@FikriMilano
Copy link
Collaborator

@MJ1998 there's none, it's just a normal text field

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: New
Development

Successfully merging this pull request may close these issues.

Cursor skipping back while start typing a value in numeric field
4 participants