iOS UITextInput autocorrection prompt (#13959)

This commit is contained in:
LongCatIsLooong 2020-04-07 14:45:59 -07:00 committed by GitHub
parent 1a0932860b
commit e59543708d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 88 additions and 27 deletions

View File

@ -868,6 +868,7 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPluginA
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputDelegate.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.m
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterUmbrellaImport.m
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterView.mm

View File

@ -598,6 +598,13 @@ NSString* const FlutterDefaultDartEntrypoint = nil;
arguments:@[ @(client), actionString ]];
}
- (void)showAutocorrectionPromptRectForStart:(NSUInteger)start
end:(NSUInteger)end
withClient:(int)client {
[_textInputChannel.get() invokeMethod:@"TextInputClient.showAutocorrectionPromptRect"
arguments:@[ @(client), @(start), @(end) ]];
}
#pragma mark - Screenshot Delegate
- (flutter::Rasterizer::Screenshot)takeScreenshot:(flutter::Rasterizer::ScreenshotType)type

View File

@ -34,7 +34,9 @@ typedef NS_ENUM(NSInteger, FlutterFloatingCursorDragState) {
- (void)updateFloatingCursor:(FlutterFloatingCursorDragState)state
withClient:(int)client
withPosition:(NSDictionary*)point;
- (void)showAutocorrectionPromptRectForStart:(NSUInteger)start
end:(NSUInteger)end
withClient:(int)client;
@end
#endif // SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTERTEXTINPUTDELEGATE_H_

View File

@ -36,6 +36,9 @@
@end
/** A range of text in the buffer of a Flutter text editing widget. */
#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
FLUTTER_EXPORT
#endif
@interface FlutterTextRange : UITextRange <NSCopying>
@property(nonatomic, readonly) NSRange range;
@ -44,4 +47,32 @@
@end
#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
FLUTTER_EXPORT
#endif
@interface FlutterTextInputView : UIView <UITextInput>
// UITextInput
@property(nonatomic, readonly) NSMutableString* text;
@property(nonatomic, readonly) NSMutableString* markedText;
@property(readwrite, copy) UITextRange* selectedTextRange;
@property(nonatomic, strong) UITextRange* markedTextRange;
@property(nonatomic, copy) NSDictionary* markedTextStyle;
@property(nonatomic, assign) id<UITextInputDelegate> inputDelegate;
// UITextInputTraits
@property(nonatomic) UITextAutocapitalizationType autocapitalizationType;
@property(nonatomic) UITextAutocorrectionType autocorrectionType;
@property(nonatomic) UITextSpellCheckingType spellCheckingType;
@property(nonatomic) BOOL enablesReturnKeyAutomatically;
@property(nonatomic) UIKeyboardAppearance keyboardAppearance;
@property(nonatomic) UIKeyboardType keyboardType;
@property(nonatomic) UIReturnKeyType returnKeyType;
@property(nonatomic, getter=isSecureTextEntry) BOOL secureTextEntry;
@property(nonatomic) UITextSmartQuotesType smartQuotesType API_AVAILABLE(ios(11.0));
@property(nonatomic) UITextSmartDashesType smartDashesType API_AVAILABLE(ios(11.0));
@property(nonatomic, assign) id<FlutterTextInputDelegate> textInputDelegate;
@end
#endif // SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTERTEXTINPUTPLUGIN_H_

View File

@ -140,32 +140,6 @@ static UIReturnKeyType ToUIReturnKeyType(NSString* inputType) {
@end
@interface FlutterTextInputView : UIView <UITextInput>
// UITextInput
@property(nonatomic, readonly) NSMutableString* text;
@property(nonatomic, readonly) NSMutableString* markedText;
@property(readwrite, copy) UITextRange* selectedTextRange;
@property(nonatomic, strong) UITextRange* markedTextRange;
@property(nonatomic, copy) NSDictionary* markedTextStyle;
@property(nonatomic, assign) id<UITextInputDelegate> inputDelegate;
// UITextInputTraits
@property(nonatomic) UITextAutocapitalizationType autocapitalizationType;
@property(nonatomic) UITextAutocorrectionType autocorrectionType;
@property(nonatomic) UITextSpellCheckingType spellCheckingType;
@property(nonatomic) BOOL enablesReturnKeyAutomatically;
@property(nonatomic) UIKeyboardAppearance keyboardAppearance;
@property(nonatomic) UIKeyboardType keyboardType;
@property(nonatomic) UIReturnKeyType returnKeyType;
@property(nonatomic, getter=isSecureTextEntry) BOOL secureTextEntry;
@property(nonatomic) UITextSmartQuotesType smartQuotesType API_AVAILABLE(ios(11.0));
@property(nonatomic) UITextSmartDashesType smartDashesType API_AVAILABLE(ios(11.0));
@property(nonatomic, assign) id<FlutterTextInputDelegate> textInputDelegate;
@end
@implementation FlutterTextInputView {
int _textInputClient;
const char* _selectionAffinity;
@ -554,6 +528,16 @@ static UIReturnKeyType ToUIReturnKeyType(NSString* inputType) {
// physical keyboard.
- (CGRect)firstRectForRange:(UITextRange*)range {
// multi-stage text is handled somewhere else.
if (_markedTextRange != nil) {
return CGRectZero;
}
NSUInteger start = ((FlutterTextPosition*)range.start).index;
NSUInteger end = ((FlutterTextPosition*)range.end).index;
[_textInputDelegate showAutocorrectionPromptRectForStart:start
end:end
withClient:_textInputClient];
// TODO(cbracken) Implement.
return CGRectZero;
}

View File

@ -0,0 +1,32 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import <OCMock/OCMock.h>
#import <XCTest/XCTest.h>
#include "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h"
#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterEngine.h"
#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.h"
FLUTTER_ASSERT_ARC
@interface FlutterTextInputPluginTest : XCTestCase
@end
@implementation FlutterTextInputPluginTest
- (void)testAutocorrectionPromptRectAppears {
// Setup test.
id engine = OCMClassMock([FlutterEngine class]);
FlutterTextInputView* inputView = [[FlutterTextInputView alloc] initWithFrame:CGRectZero];
inputView.textInputDelegate = engine;
[inputView firstRectForRange:[FlutterTextRange rangeWithNSRange:NSMakeRange(0, 1)]];
// Verify behavior.
OCMVerify([engine showAutocorrectionPromptRectForStart:0 end:1 withClient:0]);
// Clean up mocks
[engine stopMocking];
}
@end

View File

@ -20,6 +20,7 @@
0D6AB6EB22BB40E700EEE540 /* FlutterEngineTest.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0D6AB6E722BB40CF00EEE540 /* FlutterEngineTest.mm */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; };
0D6AB72C22BC339F00EEE540 /* libOCMock.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D6AB72522BC336100EEE540 /* libOCMock.a */; };
0D6AB73F22BD8F0200EEE540 /* FlutterEngineConfig.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 0D6AB73E22BD8F0200EEE540 /* FlutterEngineConfig.xcconfig */; };
3D8AF6182384C5420033B95F /* FlutterTextInputPluginTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D8AF6172384C5420033B95F /* FlutterTextInputPluginTest.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -94,6 +95,7 @@
0D6AB6E722BB40CF00EEE540 /* FlutterEngineTest.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FlutterEngineTest.mm; sourceTree = "<group>"; };
0D6AB71722BC336100EEE540 /* OCMock.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = OCMock.xcodeproj; path = ../../../../../third_party/ocmock/Source/OCMock.xcodeproj; sourceTree = "<group>"; };
0D6AB73E22BD8F0200EEE540 /* FlutterEngineConfig.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = FlutterEngineConfig.xcconfig; sourceTree = "<group>"; };
3D8AF6172384C5420033B95F /* FlutterTextInputPluginTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FlutterTextInputPluginTest.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -176,6 +178,7 @@
children = (
0D52D3B622C566D50011DEBD /* FlutterBinaryMessengerRelayTest.mm */,
0D6AB6E722BB40CF00EEE540 /* FlutterEngineTest.mm */,
3D8AF6172384C5420033B95F /* FlutterTextInputPluginTest.m */,
0D17A5BF22D78FCD0057279F /* FlutterViewControllerTest.m */,
0D4C3FAF22DF9F5300A67C70 /* FlutterPluginAppLifeCycleDelegateTest.m */,
);
@ -387,6 +390,7 @@
buildActionMask = 2147483647;
files = (
0D6AB6EB22BB40E700EEE540 /* FlutterEngineTest.mm in Sources */,
3D8AF6182384C5420033B95F /* FlutterTextInputPluginTest.m in Sources */,
0D17A5C022D78FCD0057279F /* FlutterViewControllerTest.m in Sources */,
0D1CE5D8233430F400E5D880 /* FlutterChannelsTest.m in Sources */,
0D52D3BD22C566D50011DEBD /* FlutterBinaryMessengerRelayTest.mm in Sources */,