@@ -795,6 +795,7 @@ @interface FlutterTextInputView ()
795795// etc)
796796@property (nonatomic , copy ) NSString * temporarilyDeletedComposedCharacter;
797797@property (nonatomic , assign ) CGRect editMenuTargetRect;
798+ @property (nonatomic , strong ) NSArray <NSDictionary*>* editMenuItems;
798799
799800- (void )setEditableTransform : (NSArray *)matrix ;
800801@end
@@ -868,10 +869,118 @@ - (instancetype)initWithOwner:(FlutterTextInputPlugin*)textInputPlugin {
868869 return self;
869870}
870871
872+ - (void )handleSearchWebAction {
873+ NSLog (@" put search web logic here" );
874+ }
875+
876+ - (void )handleLookUpAction {
877+ NSLog (@" put look up logic here" );
878+ }
879+
880+ - (void )handleShareAction {
881+ NSLog (@" put share logic here" );
882+ }
883+
884+ // DFS algorithm to search a UICommand from the menu tree.
885+ - (UICommand*)searchCommandWithSelector : (SEL )selector
886+ element : (UIMenuElement*)element API_AVAILABLE(ios(16.0 )) {
887+ if ([element isKindOfClass: UICommand.class ]) {
888+ UICommand* command = (UICommand*)element;
889+ return command.action == selector ? command : nil ;
890+ } else if ([element isKindOfClass: UIMenu.class ]) {
891+ NSArray <UIMenuElement*>* children = ((UIMenu*)element).children ;
892+ for (UIMenuElement* child in children) {
893+ UICommand* result = [self searchCommandWithSelector: selector element: child];
894+ if (result) {
895+ return result;
896+ }
897+ }
898+ return nil ;
899+ } else {
900+ return nil ;
901+ }
902+ }
903+
904+ - (void )addBasicEditingCommandToItems : (NSMutableArray *)items
905+ action : (NSString *)action
906+ selector : (SEL )selector
907+ suggestedMenu : (UIMenu*)suggestedMenu {
908+ UICommand* command = [self searchCommandWithSelector: selector element: suggestedMenu];
909+ if (command) {
910+ [items addObject: command];
911+ }
912+ }
913+
914+ - (void )addAdditionalBasicCommandToItems : (NSMutableArray *)items
915+ action : (NSString *)action
916+ selector : (SEL )selector
917+ encodedItem : (NSDictionary <NSString*, id>*)encodedItem {
918+ NSString * title = encodedItem[@" title" ];
919+ if (title) {
920+ UICommand* command = [UICommand commandWithTitle: title
921+ image: nil
922+ action: selector
923+ propertyList: nil ];
924+ [items addObject: command];
925+ }
926+ }
927+
871928- (UIMenu*)editMenuInteraction : (UIEditMenuInteraction*)interaction
872929 menuForConfiguration : (UIEditMenuConfiguration*)configuration
873930 suggestedActions : (NSArray <UIMenuElement*>*)suggestedActions API_AVAILABLE(ios(16.0 )) {
874- return [UIMenu menuWithChildren: suggestedActions];
931+ UIMenu* suggestedMenu = [UIMenu menuWithChildren: suggestedActions];
932+ if (!_editMenuItems) {
933+ return suggestedMenu;
934+ }
935+
936+ NSMutableArray * items = [NSMutableArray array ];
937+ for (NSDictionary <NSString *, id >* encodedItem in _editMenuItems) {
938+ if ([encodedItem[@" type" ] isEqualToString: @" default" ]) {
939+ NSString * action = encodedItem[@" action" ];
940+ if ([action isEqualToString: @" copy" ]) {
941+ [self addBasicEditingCommandToItems: items
942+ action: action
943+ selector: @selector (copy: )
944+ suggestedMenu: suggestedMenu];
945+ } else if ([action isEqualToString: @" paste" ]) {
946+ [self addBasicEditingCommandToItems: items
947+ action: action
948+ selector: @selector (paste: )
949+ suggestedMenu: suggestedMenu];
950+ } else if ([action isEqualToString: @" cut" ]) {
951+ [self addBasicEditingCommandToItems: items
952+ action: action
953+ selector: @selector (cut: )
954+ suggestedMenu: suggestedMenu];
955+ } else if ([action isEqualToString: @" delete" ]) {
956+ [self addBasicEditingCommandToItems: items
957+ action: action
958+ selector: @selector (delete: )
959+ suggestedMenu: suggestedMenu];
960+ } else if ([action isEqualToString: @" selectAll" ]) {
961+ [self addBasicEditingCommandToItems: items
962+ action: action
963+ selector: @selector (selectAll: )
964+ suggestedMenu: suggestedMenu];
965+ } else if ([action isEqualToString: @" searchWeb" ]) {
966+ [self addAdditionalBasicCommandToItems: items
967+ action: action
968+ selector: @selector (handleSearchWebAction )
969+ encodedItem: encodedItem];
970+ } else if ([action isEqualToString: @" share" ]) {
971+ [self addAdditionalBasicCommandToItems: items
972+ action: action
973+ selector: @selector (handleShareAction )
974+ encodedItem: encodedItem];
975+ } else if ([action isEqualToString: @" lookUp" ]) {
976+ [self addAdditionalBasicCommandToItems: items
977+ action: action
978+ selector: @selector (handleLookUpAction )
979+ encodedItem: encodedItem];
980+ }
981+ }
982+ }
983+ return [UIMenu menuWithChildren: items];
875984}
876985
877986- (void )editMenuInteraction : (UIEditMenuInteraction*)interaction
@@ -887,8 +996,10 @@ - (CGRect)editMenuInteraction:(UIEditMenuInteraction*)interaction
887996 return _editMenuTargetRect;
888997}
889998
890- - (void )showEditMenuWithTargetRect : (CGRect)targetRect API_AVAILABLE(ios(16.0 )) {
999+ - (void )showEditMenuWithTargetRect : (CGRect)targetRect
1000+ items : (NSArray <NSDictionary*>*)items API_AVAILABLE(ios(16.0 )) {
8911001 _editMenuTargetRect = targetRect;
1002+ _editMenuItems = items;
8921003 UIEditMenuConfiguration* config =
8931004 [UIEditMenuConfiguration configurationWithIdentifier: nil sourcePoint: CGPointZero];
8941005 [self .editMenuInteraction presentEditMenuWithConfiguration: config];
@@ -2560,7 +2671,7 @@ - (BOOL)showEditMenu:(NSDictionary*)args API_AVAILABLE(ios(16.0)) {
25602671 [encodedTargetRect[@" x" ] doubleValue ], [encodedTargetRect[@" y" ] doubleValue ],
25612672 [encodedTargetRect[@" width" ] doubleValue ], [encodedTargetRect[@" height" ] doubleValue ]);
25622673 CGRect localTargetRect = [self .hostView convertRect: globalTargetRect toView: self .activeView];
2563- [self .activeView showEditMenuWithTargetRect: localTargetRect];
2674+ [self .activeView showEditMenuWithTargetRect: localTargetRect items: args[ @" items " ] ];
25642675 return YES ;
25652676}
25662677
0 commit comments