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

[RNMobile] Try fixing split/merge issue on native mobile by dropping selection update event when late #29683

Merged
merged 12 commits into from
Mar 18, 2021

Conversation

hypest
Copy link
Contributor

@hypest hypest commented Mar 9, 2021

Description

This is another attempt to fix #29478. Opening this set of PRs to have a view of what CI thinks.

There's this prior PR already but since @jd-alexander noticed that the issue still happens sometimes, I gave it a different attempt. We'll collaborate on which one to keep if any.

gutenberg-mobile PR: wordpress-mobile/gutenberg-mobile#3239

How has this been tested?

Manual tests of splitting and merging paragraph blocks. Also, we ran the "Writing flow" section of the manual testsuite for native mobile.

Types of changes

  • Started bumping the event counter number on the JS side to denote a need to force update the native side. The RichText component bumps the lastEventCount (only for Android, the iOS case still uses undefined to pass the same "message") and the native Aztec wrapper component uses that number to synchronize the counter it keeps internally. Note, the JS side doesn't directly change the native counter; the sync happens in native to ensure that there's no race condition happening by two entities trying to change the same counter variable.
  • Started dropping the events that reach the JS side from Aztec but are late.

Individual changes in the native Aztec wrapper

  1. capture the new event counter sent from the JS side
  2. In native Aztec wrapper, sync from the JS side counter when the native component tries to increment the counter. Essentially, instead of just incrementing the native counter, syncing it first and then incrementing.

Individual changes in the RichText component on the JS side

  1. Replace the this.lastEventCount = undefined with this.manipulateEventCounterToForceNativeToRefresh() as the way to force the native Android component to update. It was needed to change this for all occurrences otherwise there were issues in various writing flow situations.
  2. drop the onChangeFromAztec event if it's late.
  3. drop the handleDelete event if late.
  4. Introduce the shouldDropEventFromAztec function that checks if the event counter of an event is late compared to the counter kept locally in RichText. Only for Android though. For iOS the function always returns false as the counter based dropping mechanism doesn't exist on iOS, doesn't seem to be needed anyway, yet at least.
  5. drop the onSelectionChangeFromAztec event if late. This is the main fix for the issue at hand actually, since that event is holding a version of the text before the split, and we don't want to use that text.
  6. Introduce the manipulateEventCounterToForceNativeToRefresh() function, that bumps the event counter for Android. Using this function simplifies the callsites trying to trigger the force update of the native side.

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • I've tested my changes with keyboard and screen readers.
  • My code has proper inline documentation.
  • I've included developer documentation if appropriate.
  • I've updated all React Native files affected by any refactorings/renamings in this PR.

@github-actions
Copy link

github-actions bot commented Mar 9, 2021

Size Change: 0 B

Total Size: 1.4 MB

ℹ️ View Unchanged
Filename Size Change
build/a11y/index.js 1.14 kB 0 B
build/annotations/index.js 3.78 kB 0 B
build/api-fetch/index.js 3.4 kB 0 B
build/autop/index.js 2.82 kB 0 B
build/blob/index.js 665 B 0 B
build/block-directory/index.js 8.63 kB 0 B
build/block-directory/style-rtl.css 1 kB 0 B
build/block-directory/style.css 1.01 kB 0 B
build/block-editor/index.js 126 kB 0 B
build/block-editor/style-rtl.css 12.4 kB 0 B
build/block-editor/style.css 12.4 kB 0 B
build/block-library/blocks/archives/editor-rtl.css 61 B 0 B
build/block-library/blocks/archives/editor.css 60 B 0 B
build/block-library/blocks/audio/editor-rtl.css 58 B 0 B
build/block-library/blocks/audio/editor.css 58 B 0 B
build/block-library/blocks/audio/style-rtl.css 112 B 0 B
build/block-library/blocks/audio/style.css 112 B 0 B
build/block-library/blocks/block/editor-rtl.css 161 B 0 B
build/block-library/blocks/block/editor.css 161 B 0 B
build/block-library/blocks/button/editor-rtl.css 475 B 0 B
build/block-library/blocks/button/editor.css 474 B 0 B
build/block-library/blocks/button/style-rtl.css 479 B 0 B
build/block-library/blocks/button/style.css 479 B 0 B
build/block-library/blocks/buttons/editor-rtl.css 315 B 0 B
build/block-library/blocks/buttons/editor.css 315 B 0 B
build/block-library/blocks/buttons/style-rtl.css 364 B 0 B
build/block-library/blocks/buttons/style.css 363 B 0 B
build/block-library/blocks/calendar/style-rtl.css 208 B 0 B
build/block-library/blocks/calendar/style.css 208 B 0 B
build/block-library/blocks/categories/editor-rtl.css 84 B 0 B
build/block-library/blocks/categories/editor.css 83 B 0 B
build/block-library/blocks/categories/style-rtl.css 79 B 0 B
build/block-library/blocks/categories/style.css 79 B 0 B
build/block-library/blocks/code/style-rtl.css 90 B 0 B
build/block-library/blocks/code/style.css 90 B 0 B
build/block-library/blocks/columns/editor-rtl.css 190 B 0 B
build/block-library/blocks/columns/editor.css 190 B 0 B
build/block-library/blocks/columns/style-rtl.css 421 B 0 B
build/block-library/blocks/columns/style.css 421 B 0 B
build/block-library/blocks/cover/editor-rtl.css 605 B 0 B
build/block-library/blocks/cover/editor.css 605 B 0 B
build/block-library/blocks/cover/style-rtl.css 1.24 kB 0 B
build/block-library/blocks/cover/style.css 1.24 kB 0 B
build/block-library/blocks/embed/editor-rtl.css 486 B 0 B
build/block-library/blocks/embed/editor.css 486 B 0 B
build/block-library/blocks/embed/style-rtl.css 401 B 0 B
build/block-library/blocks/embed/style.css 400 B 0 B
build/block-library/blocks/file/editor-rtl.css 199 B 0 B
build/block-library/blocks/file/editor.css 198 B 0 B
build/block-library/blocks/file/style-rtl.css 248 B 0 B
build/block-library/blocks/file/style.css 248 B 0 B
build/block-library/blocks/freeform/editor-rtl.css 2.46 kB 0 B
build/block-library/blocks/freeform/editor.css 2.46 kB 0 B
build/block-library/blocks/gallery/editor-rtl.css 704 B 0 B
build/block-library/blocks/gallery/editor.css 705 B 0 B
build/block-library/blocks/gallery/style-rtl.css 1.11 kB 0 B
build/block-library/blocks/gallery/style.css 1.1 kB 0 B
build/block-library/blocks/group/editor-rtl.css 160 B 0 B
build/block-library/blocks/group/editor.css 160 B 0 B
build/block-library/blocks/group/style-rtl.css 57 B 0 B
build/block-library/blocks/group/style.css 57 B 0 B
build/block-library/blocks/heading/editor-rtl.css 129 B 0 B
build/block-library/blocks/heading/editor.css 129 B 0 B
build/block-library/blocks/heading/style-rtl.css 76 B 0 B
build/block-library/blocks/heading/style.css 76 B 0 B
build/block-library/blocks/html/editor-rtl.css 281 B 0 B
build/block-library/blocks/html/editor.css 281 B 0 B
build/block-library/blocks/image/editor-rtl.css 717 B 0 B
build/block-library/blocks/image/editor.css 716 B 0 B
build/block-library/blocks/image/style-rtl.css 476 B 0 B
build/block-library/blocks/image/style.css 478 B 0 B
build/block-library/blocks/latest-comments/editor-rtl.css 159 B 0 B
build/block-library/blocks/latest-comments/editor.css 158 B 0 B
build/block-library/blocks/latest-comments/style-rtl.css 269 B 0 B
build/block-library/blocks/latest-comments/style.css 269 B 0 B
build/block-library/blocks/latest-posts/editor-rtl.css 137 B 0 B
build/block-library/blocks/latest-posts/editor.css 137 B 0 B
build/block-library/blocks/latest-posts/style-rtl.css 523 B 0 B
build/block-library/blocks/latest-posts/style.css 522 B 0 B
build/block-library/blocks/list/editor-rtl.css 65 B 0 B
build/block-library/blocks/list/editor.css 65 B 0 B
build/block-library/blocks/list/style-rtl.css 63 B 0 B
build/block-library/blocks/list/style.css 63 B 0 B
build/block-library/blocks/media-text/editor-rtl.css 191 B 0 B
build/block-library/blocks/media-text/editor.css 191 B 0 B
build/block-library/blocks/media-text/style-rtl.css 535 B 0 B
build/block-library/blocks/media-text/style.css 532 B 0 B
build/block-library/blocks/more/editor-rtl.css 434 B 0 B
build/block-library/blocks/more/editor.css 434 B 0 B
build/block-library/blocks/navigation-link/editor-rtl.css 626 B 0 B
build/block-library/blocks/navigation-link/editor.css 627 B 0 B
build/block-library/blocks/navigation-link/style-rtl.css 680 B 0 B
build/block-library/blocks/navigation-link/style.css 678 B 0 B
build/block-library/blocks/navigation/editor-rtl.css 1.11 kB 0 B
build/block-library/blocks/navigation/editor.css 1.11 kB 0 B
build/block-library/blocks/navigation/style-rtl.css 204 B 0 B
build/block-library/blocks/navigation/style.css 205 B 0 B
build/block-library/blocks/nextpage/editor-rtl.css 395 B 0 B
build/block-library/blocks/nextpage/editor.css 395 B 0 B
build/block-library/blocks/page-list/editor-rtl.css 170 B 0 B
build/block-library/blocks/page-list/editor.css 170 B 0 B
build/block-library/blocks/page-list/style-rtl.css 537 B 0 B
build/block-library/blocks/page-list/style.css 536 B 0 B
build/block-library/blocks/paragraph/editor-rtl.css 157 B 0 B
build/block-library/blocks/paragraph/editor.css 157 B 0 B
build/block-library/blocks/paragraph/style-rtl.css 247 B 0 B
build/block-library/blocks/paragraph/style.css 248 B 0 B
build/block-library/blocks/post-author/editor-rtl.css 209 B 0 B
build/block-library/blocks/post-author/editor.css 209 B 0 B
build/block-library/blocks/post-author/style-rtl.css 183 B 0 B
build/block-library/blocks/post-author/style.css 184 B 0 B
build/block-library/blocks/post-comments-form/style-rtl.css 250 B 0 B
build/block-library/blocks/post-comments-form/style.css 250 B 0 B
build/block-library/blocks/post-content/editor-rtl.css 139 B 0 B
build/block-library/blocks/post-content/editor.css 139 B 0 B
build/block-library/blocks/post-excerpt/editor-rtl.css 73 B 0 B
build/block-library/blocks/post-excerpt/editor.css 73 B 0 B
build/block-library/blocks/post-featured-image/editor-rtl.css 338 B 0 B
build/block-library/blocks/post-featured-image/editor.css 338 B 0 B
build/block-library/blocks/post-featured-image/style-rtl.css 100 B 0 B
build/block-library/blocks/post-featured-image/style.css 100 B 0 B
build/block-library/blocks/preformatted/style-rtl.css 63 B 0 B
build/block-library/blocks/preformatted/style.css 63 B 0 B
build/block-library/blocks/pullquote/editor-rtl.css 183 B 0 B
build/block-library/blocks/pullquote/editor.css 183 B 0 B
build/block-library/blocks/pullquote/style-rtl.css 318 B 0 B
build/block-library/blocks/pullquote/style.css 318 B 0 B
build/block-library/blocks/query-loop/editor-rtl.css 90 B 0 B
build/block-library/blocks/query-loop/editor.css 89 B 0 B
build/block-library/blocks/query-loop/style-rtl.css 315 B 0 B
build/block-library/blocks/query-loop/style.css 317 B 0 B
build/block-library/blocks/query-pagination-numbers/editor-rtl.css 122 B 0 B
build/block-library/blocks/query-pagination-numbers/editor.css 121 B 0 B
build/block-library/blocks/query-pagination/editor-rtl.css 270 B 0 B
build/block-library/blocks/query-pagination/editor.css 262 B 0 B
build/block-library/blocks/query-pagination/style-rtl.css 168 B 0 B
build/block-library/blocks/query-pagination/style.css 168 B 0 B
build/block-library/blocks/query-title/editor-rtl.css 86 B 0 B
build/block-library/blocks/query-title/editor.css 86 B 0 B
build/block-library/blocks/query/editor-rtl.css 820 B 0 B
build/block-library/blocks/query/editor.css 819 B 0 B
build/block-library/blocks/quote/editor-rtl.css 61 B 0 B
build/block-library/blocks/quote/editor.css 61 B 0 B
build/block-library/blocks/quote/style-rtl.css 169 B 0 B
build/block-library/blocks/quote/style.css 169 B 0 B
build/block-library/blocks/rss/editor-rtl.css 201 B 0 B
build/block-library/blocks/rss/editor.css 202 B 0 B
build/block-library/blocks/rss/style-rtl.css 290 B 0 B
build/block-library/blocks/rss/style.css 290 B 0 B
build/block-library/blocks/search/editor-rtl.css 165 B 0 B
build/block-library/blocks/search/editor.css 165 B 0 B
build/block-library/blocks/search/style-rtl.css 342 B 0 B
build/block-library/blocks/search/style.css 344 B 0 B
build/block-library/blocks/separator/editor-rtl.css 99 B 0 B
build/block-library/blocks/separator/editor.css 99 B 0 B
build/block-library/blocks/separator/style-rtl.css 236 B 0 B
build/block-library/blocks/separator/style.css 236 B 0 B
build/block-library/blocks/shortcode/editor-rtl.css 512 B 0 B
build/block-library/blocks/shortcode/editor.css 512 B 0 B
build/block-library/blocks/site-logo/editor-rtl.css 201 B 0 B
build/block-library/blocks/site-logo/editor.css 201 B 0 B
build/block-library/blocks/site-logo/style-rtl.css 115 B 0 B
build/block-library/blocks/site-logo/style.css 115 B 0 B
build/block-library/blocks/social-link/editor-rtl.css 164 B 0 B
build/block-library/blocks/social-link/editor.css 165 B 0 B
build/block-library/blocks/social-links/editor-rtl.css 776 B 0 B
build/block-library/blocks/social-links/editor.css 776 B 0 B
build/block-library/blocks/social-links/style-rtl.css 1.32 kB 0 B
build/block-library/blocks/social-links/style.css 1.33 kB 0 B
build/block-library/blocks/spacer/editor-rtl.css 317 B 0 B
build/block-library/blocks/spacer/editor.css 317 B 0 B
build/block-library/blocks/spacer/style-rtl.css 48 B 0 B
build/block-library/blocks/spacer/style.css 48 B 0 B
build/block-library/blocks/table/editor-rtl.css 478 B 0 B
build/block-library/blocks/table/editor.css 478 B 0 B
build/block-library/blocks/table/style-rtl.css 402 B 0 B
build/block-library/blocks/table/style.css 402 B 0 B
build/block-library/blocks/tag-cloud/editor-rtl.css 118 B 0 B
build/block-library/blocks/tag-cloud/editor.css 118 B 0 B
build/block-library/blocks/tag-cloud/style-rtl.css 94 B 0 B
build/block-library/blocks/tag-cloud/style.css 94 B 0 B
build/block-library/blocks/template-part/editor-rtl.css 552 B 0 B
build/block-library/blocks/template-part/editor.css 551 B 0 B
build/block-library/blocks/term-description/editor-rtl.css 90 B 0 B
build/block-library/blocks/term-description/editor.css 90 B 0 B
build/block-library/blocks/text-columns/editor-rtl.css 95 B 0 B
build/block-library/blocks/text-columns/editor.css 95 B 0 B
build/block-library/blocks/text-columns/style-rtl.css 166 B 0 B
build/block-library/blocks/text-columns/style.css 166 B 0 B
build/block-library/blocks/verse/editor-rtl.css 50 B 0 B
build/block-library/blocks/verse/editor.css 50 B 0 B
build/block-library/blocks/verse/style-rtl.css 87 B 0 B
build/block-library/blocks/verse/style.css 87 B 0 B
build/block-library/blocks/video/editor-rtl.css 504 B 0 B
build/block-library/blocks/video/editor.css 503 B 0 B
build/block-library/blocks/video/style-rtl.css 187 B 0 B
build/block-library/blocks/video/style.css 187 B 0 B
build/block-library/common-rtl.css 1.1 kB 0 B
build/block-library/common.css 1.1 kB 0 B
build/block-library/editor-rtl.css 9.48 kB 0 B
build/block-library/editor.css 9.48 kB 0 B
build/block-library/index.js 147 kB 0 B
build/block-library/style-rtl.css 8.88 kB 0 B
build/block-library/style.css 8.88 kB 0 B
build/block-library/theme-rtl.css 700 B 0 B
build/block-library/theme.css 701 B 0 B
build/block-serialization-default-parser/index.js 1.87 kB 0 B
build/block-serialization-spec-parser/index.js 3.06 kB 0 B
build/blocks/index.js 48.3 kB 0 B
build/components/index.js 284 kB 0 B
build/components/style-rtl.css 16.2 kB 0 B
build/components/style.css 16.2 kB 0 B
build/compose/index.js 11.2 kB 0 B
build/core-data/index.js 16.7 kB 0 B
build/customize-widgets/index.js 3.95 kB 0 B
build/customize-widgets/style-rtl.css 168 B 0 B
build/customize-widgets/style.css 168 B 0 B
build/data-controls/index.js 830 B 0 B
build/data/index.js 8.87 kB 0 B
build/date/index.js 31.8 kB 0 B
build/deprecated/index.js 768 B 0 B
build/dom-ready/index.js 576 B 0 B
build/dom/index.js 4.96 kB 0 B
build/edit-navigation/index.js 11.9 kB 0 B
build/edit-navigation/style-rtl.css 1.31 kB 0 B
build/edit-navigation/style.css 1.31 kB 0 B
build/edit-post/index.js 307 kB 0 B
build/edit-post/style-rtl.css 7.12 kB 0 B
build/edit-post/style.css 7.11 kB 0 B
build/edit-site/index.js 27.2 kB 0 B
build/edit-site/style-rtl.css 4.55 kB 0 B
build/edit-site/style.css 4.55 kB 0 B
build/edit-widgets/index.js 20.2 kB 0 B
build/edit-widgets/style-rtl.css 3.2 kB 0 B
build/edit-widgets/style.css 3.2 kB 0 B
build/editor/editor-styles-rtl.css 347 B 0 B
build/editor/editor-styles.css 347 B 0 B
build/editor/index.js 41.9 kB 0 B
build/editor/style-rtl.css 3.9 kB 0 B
build/editor/style.css 3.9 kB 0 B
build/element/index.js 4.61 kB 0 B
build/escape-html/index.js 735 B 0 B
build/format-library/index.js 6.75 kB 0 B
build/format-library/style-rtl.css 637 B 0 B
build/format-library/style.css 639 B 0 B
build/hooks/index.js 2.28 kB 0 B
build/html-entities/index.js 623 B 0 B
build/i18n/index.js 4.01 kB 0 B
build/is-shallow-equal/index.js 698 B 0 B
build/keyboard-shortcuts/index.js 2.53 kB 0 B
build/keycodes/index.js 1.95 kB 0 B
build/list-reusable-blocks/index.js 3.14 kB 0 B
build/list-reusable-blocks/style-rtl.css 629 B 0 B
build/list-reusable-blocks/style.css 628 B 0 B
build/media-utils/index.js 5.34 kB 0 B
build/notices/index.js 1.85 kB 0 B
build/nux/index.js 3.41 kB 0 B
build/nux/style-rtl.css 731 B 0 B
build/nux/style.css 727 B 0 B
build/plugins/index.js 2.89 kB 0 B
build/primitives/index.js 1.42 kB 0 B
build/priority-queue/index.js 791 B 0 B
build/react-i18n/index.js 1.46 kB 0 B
build/redux-routine/index.js 2.84 kB 0 B
build/reusable-blocks/index.js 3.78 kB 0 B
build/reusable-blocks/style-rtl.css 225 B 0 B
build/reusable-blocks/style.css 225 B 0 B
build/rich-text/index.js 13.3 kB 0 B
build/server-side-render/index.js 2.58 kB 0 B
build/shortcode/index.js 1.7 kB 0 B
build/token-list/index.js 1.27 kB 0 B
build/url/index.js 3.02 kB 0 B
build/viewport/index.js 1.86 kB 0 B
build/warning/index.js 1.14 kB 0 B
build/wordcount/index.js 1.22 kB 0 B

compressed-size-action

@enejb enejb mentioned this pull request Mar 9, 2021
7 tasks
Copy link
Contributor

@jd-alexander jd-alexander left a comment

Choose a reason for hiding this comment

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

Hi @hypest thanks for these changes. I tested the behavior and it works most of the time but similar to my solution, the bug can still occur even though the solution resolves the issue. Upon observing the content changes of the editor more closely I am realizing that after around 10 splits/merges the bug only occurs if a space is not in front of the word the caret is positioned at before enter is pressed. I am wondering if this has something to do with how the newline marker is being processed in the EnterPressedWatcher I am trying to determine a mechanism for proper diagnosis.

@jd-alexander jd-alexander added the Mobile App - i.e. Android or iOS Native mobile impl of the block editor. (Note: used in scripts, ping mobile folks to change) label Mar 9, 2021
@hypest
Copy link
Contributor Author

hypest commented Mar 9, 2021

Thanks for giving this a test @jd-alexander !

after around 10 splits/merges the bug only occurs if a space is not in front of the word the caret is positioned at before enter is pressed

Hmm, can you try capturing a video perhaps of the situation? Also, just to cover various cases, does that happen to you both on physical devices and on emulators?

I've tried to split+merge in the middle of a word (so to not have spaces around the caret) many times in a row and I can't reproduce on my Pixel 2XL Android 10.

@hypest
Copy link
Contributor Author

hypest commented Mar 9, 2021

Noticed that the solution as is introduces a bug:

  1. Split a paragraph and merge it again (e.g. by backspacing)
  2. Move the caret to another position in the paragraph by tapping on the new position
  3. Notice the logcat/console message Dropping onSelectionChange from Aztec as its event counter is older than latest sent to the native side. It shouldn't need to happen as the new caret positioning is intentional.
  4. Try to split the paragraph in the new caret location. The split will actually happen in the position it happened in step 1 💥

Need to work some more on this.
EDIT: added a commit about it and some comments, see below: #29683 (comment).

@jd-alexander
Copy link
Contributor

Thanks for giving this a test @jd-alexander !

after around 10 splits/merges the bug only occurs if a space is not in front of the word the caret is positioned at before enter is pressed

Hmm, can you try capturing a video perhaps of the situation? Also, just to cover various cases, does that happen to you both on physical devices and on emulators?

I've tried to split+merge in the middle of a word (so to not have spaces around the caret) many times in a row and I can't reproduce on my Pixel 2XL Android 10.

Understood! I am going to attempt to reproduce and share a video from my device. IIRC, I observed the behavior on my emulator so my reproduction attempt now will give me a solid idea of the bug's occurrence.

So the steps I have been using are.

  1. Paste content into a paragraph block.
  2. Put the caret in the middle of the content directly in front of a word.
  3. Press enter.
  4. Put the caret at the end of the first word in the newly created paragraph block that has the second part of the split content.
  5. Press backspace until the block merges.
  6. Repeat steps 2 - 5 consecutively until the content duplication is observed.

This way, when the JS bumps the counter, the native side picks it up and
increments from there.
@hypest
Copy link
Contributor Author

hypest commented Mar 10, 2021

  1. Try to split the paragraph in the new caret location. The split will actually happen in the position it happened in step 1 💥

Added b20609c to sync the two sides (JS, native) to avoid dropping all those events that started be marked as late. Generally this can be a risky change, leading to potential race conditions or bugs in places not really foreseen... this will need good testing.

@hypest
Copy link
Contributor Author

hypest commented Mar 10, 2021

Put the caret at the end of the first word in the newly created paragraph block that has the second part of the split content.

Ah, thanks for the steps Joel! That step of putting the caret deeper in the second paragraph is one I wasn't doing before.
I tried the loop a few times but haven't reproduced yet on my physical Pixel 2XL. Will try an emulator too.

@hypest
Copy link
Contributor Author

hypest commented Mar 10, 2021

I observed the behavior on my emulator

Actually @jd-alexander , can you share the emulator details too? Device frame, API level, CPU/ABI, with Play Store or not? Thanks!

In the meantime, I tried on a "Pixel 2 XL, API 29, x86, no Play Store" emulator and couldn't reproduce.

@jd-alexander
Copy link
Contributor

jd-alexander commented Mar 10, 2021

I observed the behavior on my emulator

Actually @jd-alexander , can you share the emulator details too? Device frame, API level, CPU/ABI, with Play Store or not? Thanks!

In the meantime, I tried on a "Pixel 2 XL, API 29, x86" emulator and couldn't reproduce.

I was using a Pixel 3a, API 30, x86. I am going to attempt to reproduce from my side now. I am syncing up with the latest changes from this PR.

@hypest
Copy link
Contributor Author

hypest commented Mar 10, 2021

OK, I think I can consistently replicate the issue on the Pixel 3a API 11 emulator (but not at all on the physical device), here are the steps:

  1. Use WPAndroid or the demo app, happens on both for me.
  2. Use a 4 words text in the paragraph, like this one one two three four.
  3. Place the cursor at the start of the three.
  4. Hit "Enter" on the virtual keyb to split the paragraph
  5. Place the caret in the middle of the second word in the new paragraph, for example right after the f.
  6. Hit backspace (virtual keyb) until the blocks are merged
  7. Continue hitting backspace until the two is also deleted.
  8. Hit Enter to split the block again. Should now see our in the second paragraph.
  9. Hit backspace to merge back (without any other char deletions)
  10. 💥 text from the split paragraph is duplicated before the cursor ending up in a two-line paragraph with line one having one and the second line having ourour and the caret in the middle of the ourour.

Video capture of the steps and issue:

screencapture-1615373097537.mp4

@hypest
Copy link
Contributor Author

hypest commented Mar 10, 2021

Didn't have the chance to work on debugging/fixing not that there seems to be a consistent way to replicate. I did try to use more manipulateEventCounterToForceNativeToRefresh in place of this.lastEventCount = undefined to remove occurrences of Tried to bump the RichText native event counter but was 'undefined'. Aborting bump., but that didn't resolve the issue. @jd-alexander feel free to pick up as well as I'm not going to be able to work on this today, need to be at a half-day training thing, thanks!

So to drop the Aztec onChange events too, if late.
If the update was due to content change from the JS side of things, the
counter would have already been bumped in shouldComponentUpdate
(hopefully), so bumping it again in DidUpdate introduces a counter bump
that gets out-of-sync with Aztec since (the bump inside DidUpdate
doesn't cause a render and thus no new counter sent to Aztec).
@hypest
Copy link
Contributor Author

hypest commented Mar 11, 2021

Added a couple more commits to fix the issue.

The bit that kinda worries me and am not super sure it won't introduce some regression is the removal of the counter manipulation in componentDidUpdate. History of that need is buried behind the monorepo super-squash and some code/file movements prior that, making it hard to find what's the rationale/need of that manipulation in the first place. Code archeology needs more time to uncover that I guess 😬.

In the meantime, I'll resort to the testuites and manual testing to verify if some regression is introduced. Edit: the mobile testsuites here and in the gutenberg-mobile PR are green 🎉.

@jd-alexander
Copy link
Contributor

jd-alexander commented Mar 11, 2021

Added a couple more commits to fix the issue.

Thanks! I will check this out in more detail tomorrow!

The bit that kinda worries me and am not super sure it won't introduce some regression is the removal of the counter manipulation in componentDidUpdate. History of that need is buried behind the monorepo super-squash and some code/file movements prior that, making it hard to find what's the rationale/need of that manipulation in the first place. Code archeology needs more time to uncover that I guess 😬.

Exactly! Every time I try to find some history, the mono repo super squash gets in the way, so I have to utilize the debugger or search for previous PRs to create some form of history.

In the meantime, I'll resort to the testuites and manual testing to verify if some regression is introduced. Edit: the mobile testsuites here and in the gutenberg-mobile PR are green 🎉.

I appreciate the easier reproduction steps mentioned above. 🙏🏾

@jd-alexander
Copy link
Contributor

I created a test PR that generates an APK to test these changes.

@jd-alexander
Copy link
Contributor

Concern

The bit that kinda worries me and am not super sure it won't introduce some regression is the removal of the counter manipulation in componentDidUpdate.

Understood! I will investigate this!

Investigation

History of that need is buried behind the monorepo super-squash and some code/file movements prior that, making it hard to find what's the rationale/need of that manipulation in the first place. Code archeology needs more time to uncover that I guess 😬.

True. I did a bit of git sleuthing to find the introduction of the componentDidUpdate behavior in the RichText component.

  1. As you have said, I observed that the RichText component was located in packages/block-editor/src/components/rich-text/index.native.js but was later moved to https://github.com/WordPress/gutenberg/blob/trunk/packages/rich-text/src/component/index.native.js so to find the PR that added the change, I sifted through changes in packages/block-editor/src/components/rich-text/ package.

  2. Originally, the behavior was defined in [RN Mobile] Fix crash when merging block [RN Mobile] Fix crash when merging block #15392 At the time of it's implementation componentWillReceiveProps was being utilized.

componentWillReceiveProps( nextProps ) {

  1. This commit introduced the logic. componentWillReceiveProps was marked as unsafe in React 17, so a PR that brought some of the latest splitting changes from the web, and did a migration of the behavior from componentWillReceiveProps to componentDidUpdate in this commit .

Testing

Device: Google Pixel 4 XL
OS: Android 11
App: WPAndroid
Build: 99043

In the meantime, I'll resort to the testuites and manual testing to verify if some regression is introduced. Edit: the mobile testsuites here and in the gutenberg-mobile PR are green 🎉.

This is a good testing strategy. In addition to this, I used the testing strategy of the gutenberg-mobile PR that introduced the changes to verify no regressions were introduced.

I also did the splitting and merging writing flow tests.

Splitting and merging

  • TC001 - Merge after writing
  • TC002 - Merge after selection
  • TC003 - Merge after deleting text
  • TC004 - Merge after deleting all
  • TC005 - Merge multiple blocks
  • TC006 - Splitting/merge list block

Issues

Splitting/merge list block 🟡

When testing, I noticed odd behavior while trying to split the list at times. I was able to reproduce this in other versions of the app like 16.9 & 16.8, so I don't think these changes are causing this behavior. Is this a regression?

How to reproduce it:

  1. Write some items on a list block.
  2. Place the caret at the end of different items and press enter to split.
  3. Notice that sometimes it does not work as expected and causes wonky behavior.
Example
splitting.mp4

Next steps

  1. Verify that the changes introduced do not contribute to the splitting issues.
  2. Create a test iOS PR and test these changes.

@hypest
Copy link
Contributor Author

hypest commented Mar 12, 2021

This commit introduced the logic. componentWillReceiveProps was marked as unsafe in React 17, so a PR that brought some of the latest splitting changes from the web, and did a migration of the behavior from componentWillReceiveProps to componentDidUpdate in this commit .

Thanks for digging Joel, good find. Yeah, it's not clear why the set-to-undefined was exactly needed there. I'd say let's assume that it's no longer needed if all our testing works fine, especially since there's no crash introduced here (that original PR of Tug's was fixing a crash).

I also did the splitting and merging writing flow tests.

Nice to see the split/merge manual tests pass, thanks Joel!

When testing, I noticed odd behavior while trying to split the list at times. I was able to reproduce this in other versions of the app like 16.9 & 16.8, so I don't think these changes are causing this behavior. Is this a regression?

Possibly a regression yea, we should look at it separately from this PR. Haven't tried myself but looks like not a blocker for the PR.

@hypest
Copy link
Contributor Author

hypest commented Mar 12, 2021

Android Writing Flow checklist

Device: Pixel 2XL
OS: Android 11
Build: RP1A.201005.004.A1

General

  • TC001 - Paste formatted text copied from website
  • TC001 - Multiline components
    • Verse
    • Quote
    • Preformatted
    • Code (dev only)
    • Pullquote
      ⚠️ Pullquote's body in html has a single <p> with <br> in the middle. The testcase though says it should be individual <p> tags
      ⚠️ In Pullquote's citation, tapping Enter doesn't split the block, only adds a newline in the citation. In the testcase, the "Known issue" mentions that the block is also split. Maybe that behavior has changed at some point?

Rich Text Format

  • TC001 - Bold, Italic, strikethrough buttons
  • TC002 - Alignment buttons
  • TC003 - Alignment Split
  • TC004 - Link button works without selection
  • TC005 - Link button works with a selected word
  • TC006 - Adding a link from a copied URL
  • TC007 - Test format detection under the cursor
  • TC008 - Test formatting doesn't remove leading or trailing whitespace
Splitting and merging
  • TC001 - Merge after writing
  • TC002 - Merge after selection
  • TC003 - Merge after deleting text
  • TC004 - Merge after deleting all
  • TC005 - Merge multiple blocks
  • TC006 - Splitting/merge list block

Undo / Redo - Test Cases

  • TC001 - Undo/redo block actions
  • TC002 - Undo/redo text
  • TC003 - Undo/redo text format

@hypest
Copy link
Contributor Author

hypest commented Mar 12, 2021

Note: won't update the branches until we finish with the manual testing, to avoid waiting again for CI everywhere (the gutenberg-mobile side is fully green on CI atm). We can update the branches when we're ready to start merging.

@SiobhyB
Copy link
Contributor

SiobhyB commented Mar 12, 2021

Noting that I'm seeing strange behaviour when attempting to create more than one new line in the quote block. You'll see from the recording that when I attempt to create a third line, by tapping enter for the second time, the second line is lost and a new block is created:

quote.mov

There are some existing issues surrounding new lines and the quote block (wordpress-mobile/gutenberg-mobile#2498 and #27690) but this seems significantly different and isn't something I was able to replicate on my main device (running alpha-280).

I tested this on a Pixel 2 emulator.

Edited to add: I'm seeing some similarly concerning behaviour in the block's citation section, with lines actually being removed when I press enter in my testing:

citation.mov

@SiobhyB
Copy link
Contributor

SiobhyB commented Mar 12, 2021

I was able to successfully complete all of the manual tests except for the multiline components checks. If I attempt to create more than two new lines with any of the listed blocks, apart from the code block, then text disappears as explained here for the quote block. I'm going to do some more testing so that I can verify things work as expected on the main branch for me, just in case the issue is with my local environment, and will update accordingly.

General

  • TC001 - Paste formatted text copied from website
  • TC001 - Multiline components
    • Quote block
    • Verse block
    • Preformatted block
    • Code block (DEV only)
    • Pullquote block

Rich Text Format

  • TC001 - Bold, Italic, strikethrough buttons
  • TC002 - Alignment buttons
  • TC003 - Alignment Split
  • TC004 - Link button works without selection
  • TC005 - Link button works with a selected word
  • TC006 - Adding a link from a copied URL
  • TC007 - Test format detection under the cursor
  • TC008 - Test formatting doesn't remove leading or trailing whitespace
Splitting and merging
  • TC001 - Merge after writing
  • TC002 - Merge after selection
  • TC003 - Merge after deleting text
  • TC004 - Merge after deleting all
  • TC005 - Merge multiple blocks
  • TC006 - Splitting/merge list block

Undo / Redo - Test Cases

  • TC001 - Undo/redo block actions
  • TC002 - Undo/redo text
  • TC003 - Undo/redo text format

@SiobhyB
Copy link
Contributor

SiobhyB commented Mar 15, 2021

After some further testing, I found that I was able to replicate the issues I've described on the latest version of the WordPress app, so they're not specific to this branch. The issue with lines sometimes being lost is tricky to reliably replicate, which is what led to the confusion. Sorry for that! I've now created separate issues for these:

I've updated the multiline components test case with these two new known issues.

After running through the writing flow test cases again, I confirm that I wasn't able to find any issues specific to this branch.

@geriux geriux mentioned this pull request Mar 15, 2021
13 tasks
@hypest
Copy link
Contributor Author

hypest commented Mar 16, 2021

I recently encountered an issue that I think is related with the split/merge issue

👋 @mkevins, thanks for adding info here! I'm a bit confused though, Are you referring to the issue (regression actually) at hand for this PR, or some other issue? If other issue, may I suggest moving to a ticket or a different PR and we can discuss there? There are some interesting points you raise in your comment, ultimately related to GBoard suggestion service that has bitten us in the past too 😢 , and probably deserve it's own space.

If your comment is related to this PR, then I'm not sure which split/merge issue you are referring to. Is there some case this fix is missing? Just for context, the underlying issue (previously split text duplicates after merging) is caused by internal data model corruption in the RichText component, itself caused by a selectionChange event that holds obsolete data. I.e. doesn't seem to have something to do with enter-key detection. Let me know if I'm missing something 🤔.

@hypest
Copy link
Contributor Author

hypest commented Mar 16, 2021

Thanks for the detailed testing @SiobhyB !

OK, since it looks like there are no specific issues that have been found only occurring in this PR (pending @mkevins' confirmation too) I will go ahead and update the PR(s) and mark it as ready for review.

@hypest
Copy link
Contributor Author

hypest commented Mar 16, 2021

👋 @cameronvoell , added you as a reviewer as well as you've worked with Aztec too. @jd-alexander has already given a deep look but it would be nice if you had a look as well to contribute to the code-level confidence of this PR. Let me know if y'all have any thoughts about the review. Thanks!

EDIT: Noticed now that Cameron is away this week so, will remove the review request for the time being.

@mkevins
Copy link
Contributor

mkevins commented Mar 16, 2021

@mkevins, thanks for adding info here! I'm a bit confused though, Are you referring to the issue (regression actually) at hand for this PR, or some other issue?

Yes, I'm referring to the splitting and merging issue, and that I believe it could be related. Step 4 in the steps to reproduce is:

Press Enter (Intro) to split the block into two. (if using the simulator, use the device keyboard)

I noticed that @jd-alexander was also observing strange behavior in the underlying TextWatcher at EnterPressedWatcher, and a closer look at this might reveal a similar or same underlying issue, or at the very least it might help shed light on why some emulators / devices are exhibiting different behavior while testing and debugging these PRs.

If other issue, may I suggest moving to a ticket or a different PR and we can discuss there? There are some interesting points you raise in your comment, ultimately related to GBoard suggestion service that has bitten us in the past too , and probably deserve it's own space.

I agree, the gboard suggestion issues probably deserve their own space. I think it may have been useful here as well since these are inherently related due to how we are handling keypresses and text processing in our Aztec integration, and I wanted this discussion to benefit from what I'd recently discovered, in case it helped resolve the differences observed in some testing scenarios.

If your comment is related to this PR, then I'm not sure which split/merge issue you are referring to. Is there some case this fix is missing? Just for context, the underlying issue (previously split text duplicates after merging) is caused by internal data model corruption in the RichText component, itself caused by a selectionChange event that holds obsolete data. I.e. doesn't seem to have something to do with enter-key detection. Let me know if I'm missing something .

From the backscroll, it seems that for some cases (perhaps due to different emulators or physical devices being used) the issue was not fully resolved (though I'm not sure whether this is still the case 🤔 ). I provided the patch with the intention of demonstrating an approach for the gboard problem, which might address the remaining cases, if there are any.

@hypest hypest removed the request for review from cameronvoell March 17, 2021 09:35
@hypest
Copy link
Contributor Author

hypest commented Mar 17, 2021

Ah, thanks for elaborating @mkevins , I see, much appreciated. My perception at this point is that we can go ahead with the fix unless new issues are found, and the Gboard suggestions proposal can spawn out to a dedicated PR. 👍

Copy link
Contributor

@jd-alexander jd-alexander left a comment

Choose a reason for hiding this comment

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

@hypest I tested this PR again by splitting/merging content in the Paragraph and Heading block and it behaved as expected. I also noticed the WARN and LOG outputs from the event counter logic in the console when the onSelectionChange event is dropped and when lastEventCount bumps doesn't occur.

LGTM 🚢

  • We can keep an eye out for anything suspicious during our next release testing session where we will be publishing the keep block id on split revert we have been doing.

  • Also, could you please add a description of the changes to the PR since this is the solution we are going with. Thanks much :)

  • Add the respective release notes to this PR and the gb-mobile PR as well.

@hypest
Copy link
Contributor Author

hypest commented Mar 18, 2021

Thanks for the extra review pass @jd-alexander !

Also, could you please add a description of the changes to the PR since this is the solution we are going with. Thanks much :)

Sure thing and good reminder! Updated the PR description with a detailed list of the changes and context about them.

Add the respective release notes to this PR and the gb-mobile PR as well.

Added the lines! 👍

Will merge all PRs when CI gets green across the board!

@hypest
Copy link
Contributor Author

hypest commented Mar 18, 2021

All CI is green, including the extended UI tests in the gutenberg-mobile PR and the WPAndroid PR. Will do the merge domino now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Mobile App - i.e. Android or iOS Native mobile impl of the block editor. (Note: used in scripts, ping mobile folks to change)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

(Android) Splitting and merging a Paragraph/Heading block doesn't work correctly
4 participants