From 367dbeee8ccbed5177fb457119d94aeb1bd2638a Mon Sep 17 00:00:00 2001 From: Chaiwat Ekkaewnumchai Date: Thu, 7 May 2020 06:16:12 -0700 Subject: [PATCH] (client_ios) Return Tree And Path to Flipper Desktop Summary: Similar to D21040429, we need to add data sent to Flipper desktop so that we can use to retrieve necessary data. ~~The implementation is different; storing **all** component data is needed because the plugin refers to it when asked for information. This might cause an issue because we need to store more data. However, due to the sparseness of data at a single touch, this shouldn't cause any OOM.~~ Implementation Detail: - `FlipperKitLayoutPlugin.mm` - When the process finishes the tree returned is trie from root node to every node that is touched - `SKTouch.m` - `_nodeStack` keeps track of path from root to current component - `_treeStack` keeps track of current prefix tree (trie) - `continueWithChildIndex` takes care of logic for `_nodeStack` and `_treeStack` Reviewed By: Andrey-Mishanin Differential Revision: D21335956 fbshipit-source-id: 84c0cabd7399abe50cf2deaff2b01149a1a792d5 --- .../FlipperKitLayoutPlugin.mm | 27 +++++++++---- .../FlipperKitLayoutPlugin/SKTouch.h | 5 ++- .../FlipperKitLayoutPlugin/SKTouch.m | 39 ++++++++++++++----- .../SonarKitLayoutPluginTests.m | 7 +++- 4 files changed, 58 insertions(+), 20 deletions(-) diff --git a/iOS/Plugins/FlipperKitLayoutPlugin/FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.mm b/iOS/Plugins/FlipperKitLayoutPlugin/FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.mm index 2ef733b97..74d691a6d 100644 --- a/iOS/Plugins/FlipperKitLayoutPlugin/FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.mm +++ b/iOS/Plugins/FlipperKitLayoutPlugin/FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.mm @@ -321,17 +321,30 @@ __block id rootNode = _rootNode; [_tapListener listenForTapWithBlock:^(CGPoint touchPoint) { - SKTouch* touch = [[SKTouch alloc] - initWithTouchPoint:touchPoint - withRootNode:rootNode - withDescriptorMapper:self->_descriptorMapper - finishWithBlock:^(NSArray* path) { - [connection send:@"select" withParams:@{@"path" : path}]; - }]; + SKTouch* touch = + [[SKTouch alloc] initWithTouchPoint:touchPoint + withRootNode:rootNode + withDescriptorMapper:self->_descriptorMapper + finishWithBlock:^(id node) { + [self updateNodeReference:node]; + }]; SKNodeDescriptor* descriptor = [self->_descriptorMapper descriptorForClass:[rootNode class]]; [descriptor hitTest:touch forNode:rootNode]; + [touch retrieveSelectTree:^(NSDictionary* tree) { + NSMutableArray* path = [NSMutableArray new]; + NSDictionary* subtree = tree; + NSEnumerator* enumerator = [tree keyEnumerator]; + id nodeId; + while ((nodeId = [enumerator nextObject])) { + subtree = subtree[nodeId]; + [path addObject:nodeId]; + enumerator = [subtree keyEnumerator]; + } + [connection send:@"select" + withParams:@{@"path" : path, @"tree" : tree}]; + }]; }]; } else { [_tapListener unmount]; diff --git a/iOS/Plugins/FlipperKitLayoutPlugin/FlipperKitLayoutPlugin/SKTouch.h b/iOS/Plugins/FlipperKitLayoutPlugin/FlipperKitLayoutPlugin/SKTouch.h index 8b3b77f84..0f85fa543 100644 --- a/iOS/Plugins/FlipperKitLayoutPlugin/FlipperKitLayoutPlugin/SKTouch.h +++ b/iOS/Plugins/FlipperKitLayoutPlugin/FlipperKitLayoutPlugin/SKTouch.h @@ -9,7 +9,8 @@ #import "SKDescriptorMapper.h" -typedef void (^SKTouchFinishDelegate)(NSArray* path); +typedef void (^SKTouchFinishDelegate)(id currentNode); +typedef void (^SKProcessFinishDelegate)(NSDictionary* tree); @interface SKTouch : NSObject @@ -23,6 +24,8 @@ typedef void (^SKTouchFinishDelegate)(NSArray* path); - (void)finish; +- (void)retrieveSelectTree:(SKProcessFinishDelegate)callback; + - (BOOL)containedIn:(CGRect)bounds; @end diff --git a/iOS/Plugins/FlipperKitLayoutPlugin/FlipperKitLayoutPlugin/SKTouch.m b/iOS/Plugins/FlipperKitLayoutPlugin/FlipperKitLayoutPlugin/SKTouch.m index 53efa3222..6907ee20e 100644 --- a/iOS/Plugins/FlipperKitLayoutPlugin/FlipperKitLayoutPlugin/SKTouch.m +++ b/iOS/Plugins/FlipperKitLayoutPlugin/FlipperKitLayoutPlugin/SKTouch.m @@ -12,12 +12,13 @@ @implementation SKTouch { SKTouchFinishDelegate _onFinish; - NSMutableArray* _path; CGPoint _currentTouchPoint; - id _currentNode; SKDescriptorMapper* _descriptorMapper; + + NSMutableArray>* _nodeStack; + NSMutableArray* _treeStack; } - (instancetype)initWithTouchPoint:(CGPoint)touchPoint @@ -27,9 +28,11 @@ if (self = [super init]) { _onFinish = finishBlock; _currentTouchPoint = touchPoint; - _currentNode = node; _descriptorMapper = mapper; - _path = [NSMutableArray new]; + _nodeStack = [NSMutableArray new]; + [_nodeStack addObject:node]; + _treeStack = [NSMutableArray new]; + [_treeStack addObject:[[NSMutableDictionary alloc] init]]; } return self; @@ -40,18 +43,34 @@ _currentTouchPoint.x -= offset.x; _currentTouchPoint.y -= offset.y; + id currentNode = _nodeStack.lastObject; SKNodeDescriptor* descriptor = - [_descriptorMapper descriptorForClass:[_currentNode class]]; - _currentNode = [descriptor childForNode:_currentNode atIndex:childIndex]; + [_descriptorMapper descriptorForClass:[currentNode class]]; + id nextNode = [descriptor childForNode:currentNode + atIndex:childIndex]; + [_nodeStack addObject:nextNode]; + [_treeStack addObject:[[NSMutableDictionary alloc] init]]; - descriptor = [_descriptorMapper descriptorForClass:[_currentNode class]]; - [_path addObject:[descriptor identifierForNode:_currentNode]]; + descriptor = [_descriptorMapper descriptorForClass:[nextNode class]]; + NSString* currentId = [descriptor identifierForNode:nextNode]; + [descriptor hitTest:self forNode:nextNode]; - [descriptor hitTest:self forNode:_currentNode]; + // After finish this component + _currentTouchPoint.x += offset.x; + _currentTouchPoint.y += offset.y; + [_nodeStack removeLastObject]; + NSDictionary* currentDict = _treeStack.lastObject; + [_treeStack removeLastObject]; + [_treeStack.lastObject setObject:currentDict forKey:currentId]; } - (void)finish { - _onFinish(_path); + _onFinish(_nodeStack.lastObject); +} + +- (void)retrieveSelectTree:(SKProcessFinishDelegate)callback { + callback(_treeStack.lastObject); + [_treeStack removeAllObjects]; } - (BOOL)containedIn:(CGRect)bounds { diff --git a/iOS/Plugins/FlipperKitLayoutPlugin/SonarKitLayoutPluginTests/SonarKitLayoutPluginTests.m b/iOS/Plugins/FlipperKitLayoutPlugin/SonarKitLayoutPluginTests/SonarKitLayoutPluginTests.m index 41b375bdb..bd887e409 100644 --- a/iOS/Plugins/FlipperKitLayoutPlugin/SonarKitLayoutPluginTests/SonarKitLayoutPluginTests.m +++ b/iOS/Plugins/FlipperKitLayoutPlugin/SonarKitLayoutPluginTests/SonarKitLayoutPluginTests.m @@ -207,8 +207,11 @@ // Fake a tap at `testNode3` [tapListener tapAt:(CGPoint){26, 43}]; - XCTAssertTrue(([connection.sent[@"select"] - containsObject:@{@"path" : @[ @"testNode2", @"testNode3" ]}])); + NSLog(@"%@", connection.sent[@"select"]); + XCTAssertTrue(([connection.sent[@"select"] containsObject:@{ + @"path" : @[ @"testNode2", @"testNode3" ], + @"tree" : @{@"testNode2" : @{@"testNode3" : @{}}} + }])); } - (void)testSetSearchActiveMountAndUnmount {