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 List block handling on Android #928

Merged
merged 31 commits into from
May 2, 2019
Merged

Conversation

hypest
Copy link
Contributor

@hypest hypest commented Apr 25, 2019

Fixes #898 , #899 , #929

Companion PRs

Gutenberg: WordPress/gutenberg#15168
Aztec-Android: wordpress-mobile/AztecEditor-Android#812

This PR updates the way the "Enter" key is processed along with the general way changes from Aztec (Android) are updating the RN state without forcing them back to Aztec again.

Background

An Aztec-Android, the virtual keyboard has different behavior than external/hardware keyboards and the program flows through different code paths depending on whether it's the virtual keyboard or not. The key press from hardware keyboards is detected/intercepted before it changes the editor's text, the opposite happens on the virtual one. On the hardware keyboard, the event can be intercepted (and swallowed) upon detection, while on the virtual one the event will cause text change in Aztec. Then, virtual keyboards have a generally weird way to update the text, especially when auto-suggestions are enabled: a single key press may produce multiple "text-changed" events, each one with an intermediate state of the text change.

Changes

  1. comesFromAztec: A flag that signals whether a change initiated in Aztec, versus initiated by the RN app.
  2. firedAfterTextChanged: A signal from Aztec to show when was the "Enter" key fired from the system. "Before text change" means it was fired from the hardware key listener, while "after" means it was from the virtual keyboard. If "before", Aztec will not process the "Enter" event so, no list processing will happen at that level. The format-lib will handle the list processing and so, RN needs to force the processed text into Aztec. On the contrary, If the event happened "after" the text change, the RN side just needs to update its internal model, without forcing anything to Aztec since Aztec will also process the event.
  3. Won't send ReactTextChangedEvent and ReactTextInputEvent when the "Enter" key detection process is in progress in Aztec. We'll rely on the ReactAztecEnterEvent that will be sent and will have all the info we need, regarding text and caret. Introduced the EnterPressedUnderway span class to mark text as still being processed for the "Enter" key detection.
  4. Introduced the EnterPressedWatcher TextWatcher (moved it here from the Aztec project) so we can specify that we need the watcher to remove the Enter key when in an empty paragraph block. We don't specify that for the list block case because Aztec's list handling will remove the Enter on the list end anyway.

Test case A

  1. Have a list with a word as a list item
  2. Split the word by hitting "Enter" inside the word. Try both the "Enter" key on the virtual keyboard and an external key (e.g. via Vysor)
  3. The word should be split in two separate list items
  4. Tap backspace to merge the two list items. The word should merge.
  5. Try splitting and merging again a few times. It should always work normally.

Test case B

  1. Have a list with a few list items
  2. Tap "Enter" at the end of the last item to create a new item
  3. Tap "Enter" again. The list should be ended and a new paragraph block should be created

Test case C

  1. Have a list with 3 list items, the middle of which be empty
  2. Tap "Enter" in the middle item
  3. The list should be split and a new paragraph block should appear between the 2 newly split lists

Test case D

  1. Have a list with 3 list items, the middle of which be empty
  2. Place the caret at the beginning of the 3rd item and hit "Backspace"
  3. The middle item should get removed and the 3rd item becomes 2nd. On iOS in particular, the 3rd item loses its bullet.
  4. Hit "Backspace" again
  5. The list should have only one item with all the text now merged

Test case E

  1. Write fast inside a paragraph block. It should work as normal.

@hypest hypest added this to the v1.4 milestone Apr 25, 2019
@hypest hypest changed the title Fix List block handling in android Fix List block handling on Android Apr 25, 2019
@SergioEstevao
Copy link
Contributor

@hypest I did a smoke test in iOS and the lists still working well there.

@daniloercoli daniloercoli self-requested a review April 26, 2019 07:47
@mkevins
Copy link
Contributor

mkevins commented Apr 26, 2019

I tested the cases in this comment: #898 (comment) and observed that this PR fixes the described issue.

One caveat is that, while testing "Test B", the text remains after pressing [Enter] on step 4., but the bullet goes away (i.e. it does not create a new bullet).

Screencast:

start + before));
// if the "Enter" handling is underway, don't sent text change events. The ReactAztecEnterEvent will have
// the text (minus the Enter char itself).
if (mEditText.getText().getSpans(0, 0, EnterPressedUnderway.class).length == 0) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nitpick: What do you think about moving mEditText.getText().getSpans(0, 0, EnterPressedUnderway.class).length == 0 to a util method in EnterPressedUnderway or AztecText?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sounds good, will do 👍

Copy link
Contributor Author

@hypest hypest Apr 30, 2019

Choose a reason for hiding this comment

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

Done with 0417343.

@daniloercoli
Copy link
Contributor

Took me a while reviewing and checking the code on 3 repos, nice work here 🎉

I've followed the tests plan, and did other testing too, by using 3 different keyboards

  1. Samsung Keyboard
  2. GBoard
    3 AOSP keyboard
    Everything worked as expected.

I bet we should merged this ASAP, and let all the other people test the app since there are lot of changes in critical part of RichText+Aztec.

@mchowning
Copy link
Contributor

I noticed a bug on develop where creating a new line in the middle of a list will not update the cursor position if there is styling lower down on the list (i.e. the cursor would remain at the end of the line before the newly-created line). On this PR branch though, it looks like the issue is fixed! 🎉

Develop (42d8443)

output_develop

PR (57c8de0)

output_pr

@hypest
Copy link
Contributor Author

hypest commented Apr 30, 2019

One caveat is that, while testing "Test B", the text remains after pressing [Enter] on step 4., but the bullet goes away (i.e. it does not create a new bullet).

Thanks for reporting @mkevins , I've replicated that on my Pixel 2 XL. Will dig into it.

@hypest hypest marked this pull request as ready for review April 30, 2019 17:11
@hypest
Copy link
Contributor Author

hypest commented Apr 30, 2019

Found a new issue: Tapping "Enter" from the virtual keyboard in an empty paragraph block creates a new block (OK) but leaves the originating block with an empty line in it. Will work on this.

@hypest
Copy link
Contributor Author

hypest commented Apr 30, 2019

Fixed the garbage "Enter" key left in an empty paragraph with this commit: 897d272.

@hypest hypest requested a review from daniloercoli April 30, 2019 22:33
@hypest
Copy link
Contributor Author

hypest commented Apr 30, 2019

Noticed that currently (04610cc), trying to use this PR with WPAndroid fails because the compiler complains that react-native-aztec has Java8 bytecode, instructing us to add:

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

to the build.gradle file. Doing that inside <root>/WordPress/build.gradle fixes the issue but, not sure if that's the way to go. Also, not sure what exactly adds that Java8 bytecode yet.

@mchowning
Copy link
Contributor

mchowning commented May 1, 2019

not sure what exactly adds that Java8 bytecode yet

Looks like it's ReactAztecView:
mListeners.add(new EnterPressedWatcher(this, () -> shouldDeleteEnter));

The magic of a fresh pair of eyes. 😄

@hypest
Copy link
Contributor Author

hypest commented May 2, 2019

Great eye @mchowning , thanks for looking into and spotting this!

And of course, now I regret following AndroidStudio's hint to replace the interface implementation with the lambda 🤦‍♂️.

@mkevins
Copy link
Contributor

mkevins commented May 2, 2019

I've tested cases A through E on APIs 27 and 24 (emulated Pixel 2 and Nexus 5, respectively) and everything is working as expected for those cases. I tested these cases with both the host keyboard and the emulated screen keyboard and observed the same behavior for each.

A separate issue I observed while testing case C is that after splitting the list block with enter, and then pressing the undo button, the new paragraph block and second list block both disappear, and the caret moves back to the block preceding the first list block. The behavior I expected was that the list would return to its pre-split state.

Copy link
Contributor

@daniloercoli daniloercoli left a comment

Choose a reason for hiding this comment

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

Tested cases A through E on APIs 29 and 26.
Also run cut&paste and other writing flow tests on API29, everything worked as expected, and small issues or rendering glitches I found are also present on develop.

@hypest
Copy link
Contributor Author

hypest commented May 2, 2019

Merging as chatted over Slack.

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

Successfully merging this pull request may close these issues.

Half of word is gone after text is broken into two parts in List block
5 participants