Skip to content

Commit e2c12a2

Browse files
authored
Add Look Up to iOS selection controls (flutter#43308)
In native iOS, when Look Up is initiated on highlighted text, a view DDParsecCollectionViewController is presented with definitions of the the selected text if available, as well as Siri integrated suggestions. However, since the view controller is gated behind a private API, we will use [UIReferenceLibraryViewController](https://developer.apple.com/documentation/uikit/uireferencelibraryviewcontroller) instead, which is functionally identical and visually very similar. | Native | UIReferenceLibraryViewController| | ------------- | ------------- | | <img src="https://github.com/flutter/engine/assets/36148254/763004f0-970f-4d8a-9a9a-133401ef0c1b" width="360" />| <img src="https://github.com/flutter/engine/assets/36148254/b20fe03f-6c9d-4a4a-98dc-8bcd840406db" width="360" />| This PR is the engine portion of the changes that will allow this feature change. This PR addresses flutter/flutter#82907 More details are available in this [design doc](flutter.dev/go/add-missing-features-to-selection-controls)
1 parent a83e4c8 commit e2c12a2

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
115115
result([self clipboardHasStrings]);
116116
} else if ([method isEqualToString:@"LiveText.isLiveTextInputAvailable"]) {
117117
result(@([self isLiveTextInputAvailable]));
118+
} else if ([method isEqualToString:@"LookUp.invoke"]) {
119+
[self showLookUpViewController:args];
120+
result(nil);
118121
} else {
119122
result(FlutterMethodNotImplemented);
120123
}
@@ -307,6 +310,16 @@ - (BOOL)isLiveTextInputAvailable {
307310
return [[self textField] canPerformAction:@selector(captureTextFromCamera:) withSender:nil];
308311
}
309312

313+
- (void)showLookUpViewController:(NSString*)term {
314+
UIViewController* engineViewController = [_engine.get() viewController];
315+
FML_DCHECK(![engineViewController presentingViewController]);
316+
UIReferenceLibraryViewController* referenceLibraryViewController =
317+
[[[UIReferenceLibraryViewController alloc] initWithTerm:term] autorelease];
318+
[engineViewController presentViewController:referenceLibraryViewController
319+
animated:YES
320+
completion:nil];
321+
}
322+
310323
- (UITextField*)textField {
311324
if (_textField == nil) {
312325
_textField = [[UITextField alloc] init];

shell/platform/darwin/ios/framework/Source/FlutterPlatformPluginTest.mm

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,48 @@ @interface FlutterPlatformPluginTest : XCTestCase
1717

1818
@interface FlutterPlatformPlugin ()
1919
- (BOOL)isLiveTextInputAvailable;
20+
- (void)showLookUpViewController:(NSString*)term;
21+
@end
22+
23+
@interface UIViewController ()
24+
- (void)presentViewController:(UIViewController*)viewControllerToPresent
25+
animated:(BOOL)flag
26+
completion:(void (^)(void))completion;
2027
@end
2128

2229
@implementation FlutterPlatformPluginTest
2330

31+
- (void)testLookUpCallInitiated {
32+
FlutterEngine* engine = [[[FlutterEngine alloc] initWithName:@"test" project:nil] autorelease];
33+
[engine runWithEntrypoint:nil];
34+
std::unique_ptr<fml::WeakPtrFactory<FlutterEngine>> _weakFactory =
35+
std::make_unique<fml::WeakPtrFactory<FlutterEngine>>(engine);
36+
37+
XCTestExpectation* presentExpectation =
38+
[self expectationWithDescription:@"Look Up view controller presented"];
39+
40+
FlutterViewController* engineViewController = [[FlutterViewController alloc] initWithEngine:engine
41+
nibName:nil
42+
bundle:nil];
43+
FlutterViewController* mockEngineViewController = OCMPartialMock(engineViewController);
44+
45+
FlutterPlatformPlugin* plugin =
46+
[[[FlutterPlatformPlugin alloc] initWithEngine:_weakFactory->GetWeakPtr()] autorelease];
47+
FlutterPlatformPlugin* mockPlugin = OCMPartialMock(plugin);
48+
49+
FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"LookUp.invoke"
50+
arguments:@"Test"];
51+
FlutterResult result = ^(id result) {
52+
OCMVerify([mockEngineViewController
53+
presentViewController:[OCMArg isKindOfClass:[UIReferenceLibraryViewController class]]
54+
animated:YES
55+
completion:nil]);
56+
[presentExpectation fulfill];
57+
};
58+
[mockPlugin handleMethodCall:methodCall result:result];
59+
[self waitForExpectationsWithTimeout:2 handler:nil];
60+
}
61+
2462
- (void)testClipboardHasCorrectStrings {
2563
[UIPasteboard generalPasteboard].string = nil;
2664
FlutterEngine* engine = [[[FlutterEngine alloc] initWithName:@"test" project:nil] autorelease];

0 commit comments

Comments
 (0)