Skip to content

Conversation

@camsim99
Copy link
Contributor

@camsim99 camsim99 commented Jan 25, 2023

Add iOS spell check toolbar to show spell check suggestions, as part of #34688. Fixes #119537.

This PR will cause the following to occur on single tap (touch only) if the word tapped is misspelled:

  • The word will be highlighted.
  • The toolbar will appear once (after this, the text selection toolbar will be toggled on/off).
  • If a suggestion in the toolbar is clicked, the misspelled word will be replaced with that suggestion, and the word edge will be selected.

The toolbar shows on single tap up if the word tap is misspelled. Otherwise, the normal behavior takes precedent.

Pre-launch Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read and followed the Flutter Style Guide, including Features we expect every widget to implement.
  • I signed the CLA.
  • I listed at least one issue that this PR fixes in the description above.
  • I updated/added relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or this PR is test-exempt.
  • All existing and new tests are passing.

@flutter-dashboard flutter-dashboard bot added a: text input Entering text in a text field or keyboard related problems f: cupertino flutter/packages/flutter/cupertino repository f: material design flutter/packages/flutter/material repository. framework flutter/packages/flutter repository. See also f: labels. labels Jan 25, 2023

/// Replace composing region with specified text.
void replaceComposingRegion(SelectionChangedCause cause, String text) {
void replaceComposingRegion({required SelectionChangedCause cause, required String text, TextRange? composingRegionRange, bool shouldSelectWordEdgeAfterReplacement = false}) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Particularly looking for feedback here. Need a way to do this same logic without access to the composing region for iOS, and this is what I came up with. Also considered a separate method for that case.

Copy link
Contributor

Choose a reason for hiding this comment

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

Check out ReplaceTextIntent. I think it basically does the same thing as this and the API is nearly identical, so I think you're on the right track. I would just make these parameters match as closely with those as possible in name and order.

I wonder if this could be somehow combined with _replaceText, which uses ReplaceTextIntent in this file?

Also, maybe Android should be using this full API anyway, instead of relying on the composing region here. Especially since non-Gboard IMEs might not have a composing region, either. Maybe that's not this PR's responsibility, though.

Then I would drop the "composing region" terminology from this method.

This could be a breaking change so keep an eye out, but it's probably very unlikely since this was just released.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We will ultimately need to move away from using the composing region to fix the Samsung and iOS issue (#119534), so I took your advice on not using it for Android or iOS. This method uses _replaceText already, which is used in other ways, as well, so I'm not sure if we should combine it. Maybe I could name this something like replaceTextFromToolbar since it contains toolbar-specific behavior.

Copy link
Contributor

Choose a reason for hiding this comment

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

I talked to @LongCatIsLooong and @Renzo-Olivares about this. We came to some good conclusions about how to organize the code that updates TextEditingValue in EditableText, but I'm worried they won't be possible here...

We'd like to keep all mutations of TextEditingValue like this in userUpdateTextEditingValue. So in this case that would mean deleting replaceComposingRegion/replaceText and putting all of that logic inside of SpellCheckSuggestionsToolbar. The one reason I'm not sure if that will work is the call to _didChangeTextEditingValue, which is private...

Can you try this out and see if you can get it to work without being able to call _didChangeTextEditingValue directly? If not we're probably ok to turn this into a public replaceWithSuggestion method or something like that. Currently the other toolbar buttons like cut/copy/paste all have their own public methods on EditableTextState, so it wouldn't be too terrible if this has a public method too.

@camsim99 camsim99 marked this pull request as ready for review February 3, 2023 20:34
@camsim99 camsim99 requested a review from justinmc February 3, 2023 21:16
Copy link
Contributor

@justinmc justinmc left a comment

Choose a reason for hiding this comment

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

Looking good, mostly small stuff besides some suggestions you asked for on replaceComposingRegion. Excited for this PR.

Comment on lines 2362 to 2364
if (shouldSelectWordEdgeAfterReplacement) {
renderEditable.selectWordEdge(cause: cause);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it work out if it were the caller's responsibility to call selectWordEdge after calling this if they want that behavior?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I mean as long as they call it, it should be fine. Otherwise, the word would stay highlighted after the replacement was made until another tap was made.

expect(state.showSpellCheckSuggestionsToolbarCalled, isFalse);
expect(state.toggleToolbarCalled, isTrue);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS }));

Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible to do one test that does the full cycle of 1. tap misspelled word 2. tap suggestion in the toolbar 3. expect the suggestion to have replaced the misspelled word.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This sort of behavior is tested in editable_text_test.dart, so I'll try adding a test for at least 2/3 there. And keep 1 tested here, like with the Material style toolbar.

Copy link
Contributor

Choose a reason for hiding this comment

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

It looks fine to me now, thanks.

}
buttonItems.add(ContextMenuButtonItem(
onPressed: () {
if (!editableTextState.mounted) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah this is what I meant. Looks like the failure was caused by Path.combine not being implemented by the HTML renderer, but I double this mounted check is the direct cause of that failure.

selection: TextSelection(affinity: TextAffinity.upstream, baseOffset: 0, extentOffset: 4),
);
controller.value = value;
await tester.pumpWidget(
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: This block should be outdented here.

Copy link
Contributor

Choose a reason for hiding this comment

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

This still looks like it needs its indentation fixed.

@justinmc
Copy link
Contributor

The actual setting of the updated TextEditingValue is what seems to cause this strange test failure. All the suspicious things from postFrameCallbacks etc. didn't seem to fix it though. I'll take a closer look if I have time.

Copy link
Contributor

@justinmc justinmc left a comment

Choose a reason for hiding this comment

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

LGTM 👍

// Spell check suggestions toolbars are intended to be shown on non-web
// platforms. Additionally, the Cupertino style toolbar can't be drawn on
// the web with the HTML renderer due to
// https://github.com/flutter/flutter/issues/44572.
Copy link
Contributor

Choose a reason for hiding this comment

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

I just created an issue specific to this, can you link to that one instead? #123560

}

/// Replace composing region with specified text.
void replaceComposingRegion(SelectionChangedCause cause, String text) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks like Google tests passed 👍

selection: TextSelection(affinity: TextAffinity.upstream, baseOffset: 0, extentOffset: 4),
);
controller.value = value;
await tester.pumpWidget(
Copy link
Contributor

Choose a reason for hiding this comment

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

This still looks like it needs its indentation fixed.

@camsim99 camsim99 added the autosubmit Merge PR when tree becomes green via auto submit App label Mar 31, 2023
@auto-submit auto-submit bot merged commit 52cacd9 into flutter:master Mar 31, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Apr 1, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Apr 1, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Apr 1, 2023
exaby73 pushed a commit to NevercodeHQ/flutter that referenced this pull request Apr 17, 2023
[iOS] Add spell check suggestions toolbar on tap
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request May 10, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request May 10, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: text input Entering text in a text field or keyboard related problems autosubmit Merge PR when tree becomes green via auto submit App f: cupertino flutter/packages/flutter/cupertino repository f: material design flutter/packages/flutter/material repository. framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[iOS] Show spell check toolbar when misspelled word is tapped

3 participants