From fe4ac525f05d4bc74ba26f2c490935193956d0a3 Mon Sep 17 00:00:00 2001 From: LinXunFeng Date: Fri, 10 Mar 2023 17:17:24 +0800 Subject: [PATCH 1/3] [ios] fix hold and drag spacebar does not move cursor when obscureText is true (#122139) --- .../Source/FlutterTextInputPlugin.mm | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm index 1ac316e819ab4..66f753ab0fd94 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm @@ -56,6 +56,7 @@ static NSString* const kDeprecatedSetSelectionRectsMethod = @"TextInput.setSelectionRects"; static NSString* const kSetSelectionRectsMethod = @"Scribble.setSelectionRects"; static NSString* const kStartLiveTextInputMethod = @"TextInput.startLiveTextInput"; +static NSString* const kUpdateConfigMethod = @"TextInput.updateConfig"; #pragma mark - TextInputConfiguration Field Names static NSString* const kSecureTextEntry = @"obscureText"; @@ -2123,6 +2124,9 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { } else if ([method isEqualToString:kStartLiveTextInputMethod]) { [self startLiveTextInput]; result(nil); + } else if ([method isEqualToString:kUpdateConfigMethod]) { + [self updateConfig:args]; + result(nil); } else { result(FlutterMethodNotImplemented); } @@ -2462,6 +2466,23 @@ - (void)clearTextInputClient { _activeView.frame = CGRectZero; } +- (void)updateConfig:(NSDictionary*)dictionary { + BOOL isSecureTextEntry = [dictionary[kSecureTextEntry] boolValue]; + for (UIView* view in self.textInputViews) { + if ([view isKindOfClass:[FlutterTextInputView class]]) { + FlutterTextInputView* inputView = (FlutterTextInputView*)view; + // The feature of holding and draging spacebar to move cursor is affected by + // secureTextEntry, so when obscureText is updated, we need to update secureTextEntry + // and call reloadInputViews. + // https://github.com/flutter/flutter/issues/122139 + if (inputView.isSecureTextEntry != isSecureTextEntry) { + inputView.secureTextEntry = isSecureTextEntry; + [inputView reloadInputViews]; + } + } + } +} + #pragma mark UIIndirectScribbleInteractionDelegate - (BOOL)indirectScribbleInteraction:(UIIndirectScribbleInteraction*)interaction From ca8094b2eb2b5ddf11b880de61c807bccde2adf7 Mon Sep 17 00:00:00 2001 From: LinXunFeng Date: Sat, 11 Mar 2023 12:12:12 +0800 Subject: [PATCH 2/3] add test --- .../Source/FlutterTextInputPluginTest.mm | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm index 84827c4722e87..9f197b659cb8c 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm @@ -164,6 +164,14 @@ - (FlutterTextRange*)getLineRangeFromTokenizer:(id)tokeniz return (FlutterTextRange*)range; } +- (void)updateConfig:(NSDictionary*)config { + FlutterMethodCall* updateConfigCall = + [FlutterMethodCall methodCallWithMethodName:@"TextInput.updateConfig" arguments:config]; + [textInputPlugin handleMethodCall:updateConfigCall + result:^(id _Nullable result){ + }]; +} + #pragma mark - Tests - (void)testWillNotCrashWhenViewControllerIsNil { @@ -647,6 +655,23 @@ - (void)testPropagatePressEventsToViewController2 { withEvent:[OCMArg isNotNil]]); } +- (void)testUpdateSecureTextEntry { + NSDictionary* config = self.mutableTemplateCopy; + [config setValue:@"YES" forKey:@"obscureText"]; + [self setClientId:123 configuration:config]; + + NSArray* inputFields = self.installedInputViews; + FlutterTextInputView* inputView = inputFields[0]; + + XCTAssertTrue(inputView.isSecureTextEntry); + + config = self.mutableTemplateCopy; + [config setValue:@"NO" forKey:@"obscureText"]; + [self updateConfig:config]; + + XCTAssertFalse(inputView.isSecureTextEntry); +} + #pragma mark - TextEditingDelta tests - (void)testTextEditingDeltasAreGeneratedOnTextInput { FlutterTextInputView* inputView = [[FlutterTextInputView alloc] initWithOwner:textInputPlugin]; From 8bd70301b57734181549763847bf282f5ff7760c Mon Sep 17 00:00:00 2001 From: LinXunFeng Date: Sat, 25 Mar 2023 12:56:51 +0800 Subject: [PATCH 3/3] supplementary test to judge whether reloadInputViews method is called --- .../ios/framework/Source/FlutterTextInputPluginTest.mm | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm index 9f197b659cb8c..c0317a289c14d 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm @@ -661,7 +661,12 @@ - (void)testUpdateSecureTextEntry { [self setClientId:123 configuration:config]; NSArray* inputFields = self.installedInputViews; - FlutterTextInputView* inputView = inputFields[0]; + FlutterTextInputView* inputView = OCMPartialMock(inputFields[0]); + + __block int callCount = 0; + OCMStub([inputView reloadInputViews]).andDo(^(NSInvocation* invocation) { + callCount++; + }); XCTAssertTrue(inputView.isSecureTextEntry); @@ -669,6 +674,7 @@ - (void)testUpdateSecureTextEntry { [config setValue:@"NO" forKey:@"obscureText"]; [self updateConfig:config]; + XCTAssertEqual(callCount, 1); XCTAssertFalse(inputView.isSecureTextEntry); }