Run CLANGFORMAT on plugins

Summary:
This diff runs CLANGFORMAT lint on plugins. I have added CLANGFORMAT as the lint engined for objc files in xplat/sonar. Right now the iOS folder is not formatted according to CLANGFORMAT.

Ran `arc lint -a --paths-cmd "find ./iOS/Plugins -type f" --verbose`

Reviewed By: passy

Differential Revision: D19942173

fbshipit-source-id: 8b975b0a344df073b02d69cd1f9ee5629af2799d
This commit is contained in:
Pritesh Nandgaonkar
2020-02-17 10:46:43 -08:00
committed by Facebook Github Bot
parent a19a430eee
commit e8b20d5b15
101 changed files with 3918 additions and 2867 deletions

View File

@@ -7,13 +7,12 @@
#if FB_SONARKIT_ENABLED #if FB_SONARKIT_ENABLED
#import <Foundation/Foundation.h>
#import <FlipperKit/FlipperPlugin.h> #import <FlipperKit/FlipperPlugin.h>
#import <Foundation/Foundation.h>
@interface FlipperKitBloksPlugin : NSObject<FlipperPlugin> @interface FlipperKitBloksPlugin : NSObject<FlipperPlugin>
- (void)logAction:(NSString *)action - (void)logAction:(NSString*)action withData:(NSDictionary*)data;
withData:(NSDictionary *)data;
@end @end

View File

@@ -12,8 +12,7 @@
#import <FlipperKit/FlipperResponder.h> #import <FlipperKit/FlipperResponder.h>
#import "Plugins.h" #import "Plugins.h"
@implementation FlipperKitBloksPlugin @implementation FlipperKitBloksPlugin {
{
id<FlipperConnection> _connection; id<FlipperConnection> _connection;
} }
@@ -33,15 +32,13 @@
return YES; return YES;
} }
- (void)logAction:(NSString *)action - (void)logAction:(NSString*)action withData:(NSDictionary*)data {
withData:(NSDictionary *)data {
[_connection send:action withParams:data]; [_connection send:action withParams:data];
} }
@end @end
void IGBloksFlipperPluginInit(FlipperClient *client) void IGBloksFlipperPluginInit(FlipperClient* client) {
{
[client addPlugin:[FlipperKitBloksPlugin new]]; [client addPlugin:[FlipperKitBloksPlugin new]];
} }

View File

@@ -5,15 +5,16 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
#import <Foundation/Foundation.h>
#import <FlipperKit/FlipperPlugin.h> #import <FlipperKit/FlipperPlugin.h>
#import <Foundation/Foundation.h>
@protocol FlipperKitExampleCommunicationResponderDelegate @protocol FlipperKitExampleCommunicationResponderDelegate
- (void)messageReceived:(NSString*)msg; - (void)messageReceived:(NSString*)msg;
@end @end
@interface FlipperKitExamplePlugin : NSObject<FlipperPlugin> @interface FlipperKitExamplePlugin : NSObject<FlipperPlugin>
@property (weak, nonatomic) id<FlipperKitExampleCommunicationResponderDelegate> delegate; @property(weak, nonatomic) id<FlipperKitExampleCommunicationResponderDelegate>
delegate;
- (instancetype)init NS_UNAVAILABLE; - (instancetype)init NS_UNAVAILABLE;
- (void)sendMessage:(NSString*)msg; - (void)sendMessage:(NSString*)msg;

View File

@@ -40,7 +40,8 @@
- (void)didConnect:(id<FlipperConnection>)connection { - (void)didConnect:(id<FlipperConnection>)connection {
__weak FlipperKitExamplePlugin* weakSelf = self; __weak FlipperKitExamplePlugin* weakSelf = self;
self.connection = connection; self.connection = connection;
[connection receive:@"displayMessage" withBlock:^(NSDictionary *params, id<FlipperResponder> responder) { [connection receive:@"displayMessage"
withBlock:^(NSDictionary* params, id<FlipperResponder> responder) {
[weakSelf.delegate messageReceived:params[@"message"]]; [weakSelf.delegate messageReceived:params[@"message"]];
[responder success:@{@"greeting" : @"Hello"}]; [responder success:@{@"greeting" : @"Hello"}];
}]; }];
@@ -63,7 +64,8 @@
} }
- (void)triggerNotification { - (void)triggerNotification {
[self.connection send:@"triggerNotification" withParams:@{@"id": @(self.triggerCount)}]; [self.connection send:@"triggerNotification"
withParams:@{@"id" : @(self.triggerCount)}];
self.triggerCount++; self.triggerCount++;
} }

View File

@@ -14,17 +14,27 @@
#import "CKComponent+Sonar.h" #import "CKComponent+Sonar.h"
static NSDictionary<NSString *, NSObject *> *CKCenterLayoutComponentCenteringOptionsParser(CKCenterLayoutComponentCenteringOptions centeringOptions) { static NSDictionary<NSString*, NSObject*>*
NSMutableDictionary<NSString *, NSObject *> *centeringDict = [NSMutableDictionary new]; CKCenterLayoutComponentCenteringOptionsParser(
centeringDict[@"centeringX"] = SKMutableObject(@((BOOL)(centeringOptions & CKCenterLayoutComponentCenteringX))); CKCenterLayoutComponentCenteringOptions centeringOptions) {
centeringDict[@"centeringY"] = SKMutableObject(@((BOOL)(centeringOptions & CKCenterLayoutComponentCenteringY))); NSMutableDictionary<NSString*, NSObject*>* centeringDict =
[NSMutableDictionary new];
centeringDict[@"centeringX"] = SKMutableObject(
@((BOOL)(centeringOptions & CKCenterLayoutComponentCenteringX)));
centeringDict[@"centeringY"] = SKMutableObject(
@((BOOL)(centeringOptions & CKCenterLayoutComponentCenteringY)));
return centeringDict; return centeringDict;
} }
static NSDictionary<NSString *, NSObject *> *CKCenterLayoutComponentSizingOptionsParser(CKCenterLayoutComponentSizingOptions sizingOptions) { static NSDictionary<NSString*, NSObject*>*
NSMutableDictionary<NSString *, NSObject *> *centeringDict = [NSMutableDictionary new]; CKCenterLayoutComponentSizingOptionsParser(
centeringDict[@"sizingMinimumX"] = SKMutableObject(@((BOOL)(sizingOptions & CKCenterLayoutComponentSizingOptionMinimumX))); CKCenterLayoutComponentSizingOptions sizingOptions) {
centeringDict[@"sizingMinimumY"] = SKMutableObject(@((BOOL)(sizingOptions & CKCenterLayoutComponentSizingOptionMinimumY))); NSMutableDictionary<NSString*, NSObject*>* centeringDict =
[NSMutableDictionary new];
centeringDict[@"sizingMinimumX"] = SKMutableObject(
@((BOOL)(sizingOptions & CKCenterLayoutComponentSizingOptionMinimumX)));
centeringDict[@"sizingMinimumY"] = SKMutableObject(
@((BOOL)(sizingOptions & CKCenterLayoutComponentSizingOptionMinimumY)));
return centeringDict; return centeringDict;
} }
@@ -40,11 +50,19 @@ struct CKCenterLayoutComponentOptionsStruct {
FB_LINKABLE(CKCenterLayoutComponent_Sonar) FB_LINKABLE(CKCenterLayoutComponent_Sonar)
@implementation CKCenterLayoutComponent (Sonar) @implementation CKCenterLayoutComponent (Sonar)
- (NSArray<SKNamed<NSDictionary<NSString *, NSObject *> *> *> *)sonar_additionalDataOverride - (NSArray<SKNamed<NSDictionary<NSString*, NSObject*>*>*>*)
{ sonar_additionalDataOverride {
return @[[SKNamed newWithName:@"CKCenterLayoutComponent" withValue:@{ return @[ [SKNamed
@"centeringOptions": SKMutableObject(CKCenterLayoutComponentCenteringOptionsParser((CKCenterLayoutComponentCenteringOptions)[[self valueForKey:@"_centeringOptions"] longValue])), newWithName:@"CKCenterLayoutComponent"
@"sizingOptions": SKMutableObject(CKCenterLayoutComponentSizingOptionsParser((CKCenterLayoutComponentSizingOptions)[[self valueForKey:@"_sizingOptions"] longValue])) withValue:@{
@"centeringOptions" :
SKMutableObject(CKCenterLayoutComponentCenteringOptionsParser(
(CKCenterLayoutComponentCenteringOptions)[
[self valueForKey:@"_centeringOptions"] longValue])),
@"sizingOptions" :
SKMutableObject(CKCenterLayoutComponentSizingOptionsParser(
(CKCenterLayoutComponentSizingOptions)[
[self valueForKey:@"_sizingOptions"] longValue]))
}] ]; }] ];
} }
@@ -57,13 +75,17 @@ FB_LINKABLE(CKCenterLayoutComponent_Sonar)
- (NSDictionary<NSString*, SKNodeDataChanged>*)sonar_getDataMutationsChanged { - (NSDictionary<NSString*, SKNodeDataChanged>*)sonar_getDataMutationsChanged {
__block CKCenterLayoutComponentOptionsStruct options; __block CKCenterLayoutComponentOptionsStruct options;
options.centeringOptions = (CKCenterLayoutComponentCenteringOptions)[[self valueForKey:@"_centeringOptions"] longValue]; options.centeringOptions = (CKCenterLayoutComponentCenteringOptions)[
options.sizingOptions = (CKCenterLayoutComponentSizingOptions)[[self valueForKey:@"_sizingOptions"] longValue]; [self valueForKey:@"_centeringOptions"] longValue];
options.sizingOptions = (CKCenterLayoutComponentSizingOptions)[
[self valueForKey:@"_sizingOptions"] longValue];
return @{ return @{
@"CKCenterLayoutComponent.centeringOptions.centeringX" : ^(NSNumber* value){ @"CKCenterLayoutComponent.centeringOptions.centeringX" : ^(NSNumber* value){
options.centeringOptions ^= CKCenterLayoutComponentCenteringX; options.centeringOptions ^= CKCenterLayoutComponentCenteringX;
return [NSValue value:&options withObjCType:@encode(CKCenterLayoutComponentOptionsStruct)]; return [NSValue value:&options
}, withObjCType:@encode(CKCenterLayoutComponentOptionsStruct)];
}
,
@"CKCenterLayoutComponent.centeringOptions.centeringY": ^(NSNumber *value) { @"CKCenterLayoutComponent.centeringOptions.centeringY": ^(NSNumber *value) {
options.centeringOptions ^= CKCenterLayoutComponentCenteringY; options.centeringOptions ^= CKCenterLayoutComponentCenteringY;
return [NSValue value:&options withObjCType:@encode(CKCenterLayoutComponentOptionsStruct)]; return [NSValue value:&options withObjCType:@encode(CKCenterLayoutComponentOptionsStruct)];
@@ -76,7 +98,8 @@ FB_LINKABLE(CKCenterLayoutComponent_Sonar)
options.sizingOptions ^= CKCenterLayoutComponentSizingOptionMinimumY; options.sizingOptions ^= CKCenterLayoutComponentSizingOptionMinimumY;
return [NSValue value:&options withObjCType:@encode(CKCenterLayoutComponentOptionsStruct)]; return [NSValue value:&options withObjCType:@encode(CKCenterLayoutComponentOptionsStruct)];
}, },
}; }
;
} }
@end @end

View File

@@ -11,54 +11,66 @@
#import <ComponentKit/CKComponentAccessibility.h> #import <ComponentKit/CKComponentAccessibility.h>
#import <ComponentKit/CKComponentController.h> #import <ComponentKit/CKComponentController.h>
#import <ComponentKit/CKComponentDebugController.h>
#import <ComponentKit/CKComponentInternal.h> #import <ComponentKit/CKComponentInternal.h>
#import <ComponentKit/CKComponentSubclass.h> #import <ComponentKit/CKComponentSubclass.h>
#import <ComponentKit/CKComponentViewConfiguration.h> #import <ComponentKit/CKComponentViewConfiguration.h>
#import <ComponentKit/CKComponentDebugController.h>
#import <ComponentKit/CKMutex.h> #import <ComponentKit/CKMutex.h>
#import <FlipperKitLayoutPlugin/SKNamed.h> #import <FlipperKitLayoutPlugin/SKNamed.h>
#import <FlipperKitLayoutPlugin/SKObject.h> #import <FlipperKitLayoutPlugin/SKObject.h>
#import <objc/runtime.h>
#import <objc/message.h> #import <objc/message.h>
#import <objc/runtime.h>
#import "CKCenterLayoutComponent+Sonar.h" #import "CKCenterLayoutComponent+Sonar.h"
#import "CKRatioLayoutComponent+Sonar.h"
#import "CKFlexboxComponent+Sonar.h" #import "CKFlexboxComponent+Sonar.h"
#import "CKInsetComponent+Sonar.h" #import "CKInsetComponent+Sonar.h"
#import "CKRatioLayoutComponent+Sonar.h"
#import "CKStatelessComponent+Sonar.h" #import "CKStatelessComponent+Sonar.h"
#import "FKDataStorageForLiveEditing.h" #import "FKDataStorageForLiveEditing.h"
#import "Utils.h" #import "Utils.h"
/** This protocol isn't actually adopted anywhere, it just lets us use the SEL below */ /** This protocol isn't actually adopted anywhere, it just lets us use the SEL
* below */
@protocol SonarKitLayoutComponentKitOverrideInformalProtocol @protocol SonarKitLayoutComponentKitOverrideInformalProtocol
- (NSString*)sonar_componentNameOverride; - (NSString*)sonar_componentNameOverride;
- (NSString*)sonar_componentDecorationOverride; - (NSString*)sonar_componentDecorationOverride;
- (NSArray<SKNamed<NSDictionary<NSString *, NSObject *> *> *> *)sonar_additionalDataOverride; - (NSArray<SKNamed<NSDictionary<NSString*, NSObject*>*>*>*)
sonar_additionalDataOverride;
@end @end
static BOOL AccessibilityContextIsDefault(CKComponentAccessibilityContext accessibilityContext) { static BOOL AccessibilityContextIsDefault(
CKComponentAccessibilityContext accessibilityContext) {
return accessibilityContext == CKComponentAccessibilityContext(); return accessibilityContext == CKComponentAccessibilityContext();
} }
static NSDictionary<NSString *, NSObject *> *AccessibilityContextDict(CKComponentAccessibilityContext accessibilityContext) { static NSDictionary<NSString*, NSObject*>* AccessibilityContextDict(
NSMutableDictionary<NSString *, NSObject *> *accessibilityDict = [NSMutableDictionary new]; CKComponentAccessibilityContext accessibilityContext) {
NSMutableDictionary<NSString*, NSObject*>* accessibilityDict =
[NSMutableDictionary new];
if (accessibilityContext.isAccessibilityElement != nil) { if (accessibilityContext.isAccessibilityElement != nil) {
accessibilityDict[@"isAccessibilityElement"] = SKObject(@([accessibilityContext.isAccessibilityElement boolValue])); accessibilityDict[@"isAccessibilityElement"] =
SKObject(@([accessibilityContext.isAccessibilityElement boolValue]));
} }
if (accessibilityContext.accessibilityLabel.hasText()) { if (accessibilityContext.accessibilityLabel.hasText()) {
accessibilityDict[@"accessibilityLabel"] = SKObject(accessibilityContext.accessibilityLabel.value()); accessibilityDict[@"accessibilityLabel"] =
SKObject(accessibilityContext.accessibilityLabel.value());
} }
if (accessibilityContext.accessibilityHint.hasText()) { if (accessibilityContext.accessibilityHint.hasText()) {
accessibilityDict[@"accessibilityHint"] = SKObject(accessibilityContext.accessibilityHint.value()); accessibilityDict[@"accessibilityHint"] =
SKObject(accessibilityContext.accessibilityHint.value());
} }
if (accessibilityContext.accessibilityValue.hasText()) { if (accessibilityContext.accessibilityValue.hasText()) {
accessibilityDict[@"accessibilityValue"] = SKObject(accessibilityContext.accessibilityValue.value()); accessibilityDict[@"accessibilityValue"] =
SKObject(accessibilityContext.accessibilityValue.value());
} }
if (accessibilityContext.accessibilityTraits != nil) { if (accessibilityContext.accessibilityTraits != nil) {
accessibilityDict[@"accessibilityTraits"] = SKObject(@([accessibilityContext.accessibilityTraits integerValue])); accessibilityDict[@"accessibilityTraits"] =
SKObject(@([accessibilityContext.accessibilityTraits integerValue]));
} }
if (accessibilityContext.accessibilityComponentAction) { if (accessibilityContext.accessibilityComponentAction) {
accessibilityDict[@"accessibilityComponentAction.identifier"] = SKObject(@(accessibilityContext.accessibilityComponentAction.identifier().c_str())); accessibilityDict[@"accessibilityComponentAction.identifier"] = SKObject(
@(accessibilityContext.accessibilityComponentAction.identifier()
.c_str()));
} }
return accessibilityDict; return accessibilityDict;
} }
@@ -70,18 +82,18 @@ static FKDataStorageForLiveEditing *_dataStorage;
static NSMutableSet<NSString*>* _swizzledClasses; static NSMutableSet<NSString*>* _swizzledClasses;
static CK::StaticMutex _mutex = CK_MUTEX_INITIALIZER; static CK::StaticMutex _mutex = CK_MUTEX_INITIALIZER;
+ (void)swizzleOriginalSEL:(SEL)originalSEL to:(SEL)replacementSEL + (void)swizzleOriginalSEL:(SEL)originalSEL to:(SEL)replacementSEL {
{
Class targetClass = self; Class targetClass = self;
Method original = class_getInstanceMethod(targetClass, originalSEL); Method original = class_getInstanceMethod(targetClass, originalSEL);
Method replacement = class_getInstanceMethod(targetClass, replacementSEL); Method replacement = class_getInstanceMethod(targetClass, replacementSEL);
BOOL didAddMethod = BOOL didAddMethod = class_addMethod(
class_addMethod(targetClass, targetClass,
originalSEL, originalSEL,
method_getImplementation(replacement), method_getImplementation(replacement),
method_getTypeEncoding(replacement)); method_getTypeEncoding(replacement));
if (didAddMethod) { if (didAddMethod) {
class_replaceMethod(targetClass, class_replaceMethod(
targetClass,
replacementSEL, replacementSEL,
method_getImplementation(original), method_getImplementation(original),
method_getTypeEncoding(original)); method_getTypeEncoding(original));
@@ -90,28 +102,27 @@ static CK::StaticMutex _mutex = CK_MUTEX_INITIALIZER;
} }
} }
- (NSString *)sonar_getName - (NSString*)sonar_getName {
{
if ([self respondsToSelector:@selector(sonar_componentNameOverride)]) { if ([self respondsToSelector:@selector(sonar_componentNameOverride)]) {
return [(id)self sonar_componentNameOverride]; return [(id)self sonar_componentNameOverride];
} }
auto const canBeReusedCounter = self.flipper_canBeReusedCounter; auto const canBeReusedCounter = self.flipper_canBeReusedCounter;
if (canBeReusedCounter > 0) { if (canBeReusedCounter > 0) {
return [NSString stringWithFormat:@"%@ (Can be reused x%lu)", NSStringFromClass([self class]), (unsigned long)canBeReusedCounter]; return [NSString stringWithFormat:@"%@ (Can be reused x%lu)",
NSStringFromClass([self class]),
(unsigned long)canBeReusedCounter];
} }
return NSStringFromClass([self class]); return NSStringFromClass([self class]);
} }
- (NSString *)sonar_getDecoration - (NSString*)sonar_getDecoration {
{
if ([self respondsToSelector:@selector(sonar_componentDecorationOverride)]) { if ([self respondsToSelector:@selector(sonar_componentDecorationOverride)]) {
return [(id)self sonar_componentDecorationOverride]; return [(id)self sonar_componentDecorationOverride];
} }
return @"componentkit"; return @"componentkit";
} }
- (NSArray<SKNamed<NSDictionary<NSString *, NSObject *> *> *> *)sonar_getData - (NSArray<SKNamed<NSDictionary<NSString*, NSObject*>*>*>*)sonar_getData {
{
static NSDictionary<NSNumber*, NSString*>* UIControlEventsEnumMap = @{ static NSDictionary<NSNumber*, NSString*>* UIControlEventsEnumMap = @{
@(UIControlEventTouchDown) : @"UIControlEventTouchDown", @(UIControlEventTouchDown) : @"UIControlEventTouchDown",
@(UIControlEventTouchDownRepeat) : @"UIControlEventTouchDownRepeat", @(UIControlEventTouchDownRepeat) : @"UIControlEventTouchDownRepeat",
@@ -124,7 +135,8 @@ static CK::StaticMutex _mutex = CK_MUTEX_INITIALIZER;
@(UIControlEventTouchCancel) : @"UIControlEventTouchTouchCancel", @(UIControlEventTouchCancel) : @"UIControlEventTouchTouchCancel",
@(UIControlEventValueChanged) : @"UIControlEventValueChanged", @(UIControlEventValueChanged) : @"UIControlEventValueChanged",
@(UIControlEventPrimaryActionTriggered): @"UIControlEventPrimaryActionTriggered", @(UIControlEventPrimaryActionTriggered) :
@"UIControlEventPrimaryActionTriggered",
@(UIControlEventEditingDidBegin) : @"UIControlEventEditingDidBegin", @(UIControlEventEditingDidBegin) : @"UIControlEventEditingDidBegin",
@(UIControlEventEditingChanged) : @"UIControlEventEditingChanged", @(UIControlEventEditingChanged) : @"UIControlEventEditingChanged",
@@ -132,32 +144,38 @@ static CK::StaticMutex _mutex = CK_MUTEX_INITIALIZER;
@(UIControlEventEditingDidEndOnExit) : @"UIControlEventEditingDidEndOnExit", @(UIControlEventEditingDidEndOnExit) : @"UIControlEventEditingDidEndOnExit",
}; };
NSMutableArray<SKNamed<NSDictionary<NSString*, NSObject*>*>*>* data =
NSMutableArray<SKNamed<NSDictionary<NSString *, NSObject *> *> *> *data = [NSMutableArray new]; [NSMutableArray new];
[data addObject:[SKNamed newWithName:@"CKComponent" [data addObject:[SKNamed newWithName:@"CKComponent"
withValue:@{ withValue:@{
@"frame" : SKObject(self.viewContext.frame), @"frame" : SKObject(self.viewContext.frame),
@"controller": SKObject(NSStringFromClass([self.controller class])), @"controller" : SKObject(
NSStringFromClass([self.controller class])),
@"size" : SKObject(ckcomponentSize([self size])), @"size" : SKObject(ckcomponentSize([self size])),
}]]; }]];
auto const canBeReusedCounter = self.flipper_canBeReusedCounter; auto const canBeReusedCounter = self.flipper_canBeReusedCounter;
if (canBeReusedCounter > 0) { if (canBeReusedCounter > 0) {
[data addObject: [SKNamed newWithName: @"Convert to CKRenderComponent" [data addObject:[SKNamed
newWithName:@"Convert to CKRenderComponent"
withValue:@{ withValue:@{
@"This component can be reused" : @"This component can be reused" : SKObject([NSString
SKObject([NSString stringWithFormat:@"%lu times", (unsigned long)canBeReusedCounter]) stringWithFormat:@"%lu times",
(unsigned long)
canBeReusedCounter])
}]]; }]];
} }
if (self.viewContext.view) { if (self.viewContext.view) {
auto _actions = _CKComponentDebugControlActionsForComponent(self); auto _actions = _CKComponentDebugControlActionsForComponent(self);
if (_actions.size() > 0) { if (_actions.size() > 0) {
NSMutableDictionary<NSString *, NSObject *> *actions = [NSMutableDictionary new]; NSMutableDictionary<NSString*, NSObject*>* actions =
[NSMutableDictionary new];
for (NSNumber* controlEvent : [UIControlEventsEnumMap allKeys]) { for (NSNumber* controlEvent : [UIControlEventsEnumMap allKeys]) {
NSMutableArray<NSDictionary<NSString *, NSObject *> *> *responders = [NSMutableArray new]; NSMutableArray<NSDictionary<NSString*, NSObject*>*>* responders =
[NSMutableArray new];
for (const auto action : _actions) { for (const auto action : _actions) {
if ((action.first & [controlEvent integerValue]) == 0) { if ((action.first & [controlEvent integerValue]) == 0) {
@@ -169,17 +187,22 @@ static CK::StaticMutex _mutex = CK_MUTEX_INITIALIZER;
if (debugTarget.isBlockBaseAction()) { if (debugTarget.isBlockBaseAction()) {
[responders addObject:@{ [responders addObject:@{
@"identifier" : SKObject(@(responder.identifier().c_str())), @"identifier" : SKObject(@(responder.identifier().c_str())),
@"selector": SKObject(NSStringFromSelector(responder.selector())), @"selector" :
SKObject(NSStringFromSelector(responder.selector())),
}]; }];
} else { } else {
id initialTarget = debugTarget.get(self); id initialTarget = debugTarget.get(self);
const CKActionInfo actionInfo = CKActionFind(responder.selector(), initialTarget); const CKActionInfo actionInfo =
CKActionFind(responder.selector(), initialTarget);
[responders addObject:@{ [responders addObject:@{
@"initialTarget": SKObject(NSStringFromClass([initialTarget class])), @"initialTarget" :
SKObject(NSStringFromClass([initialTarget class])),
@"identifier" : SKObject(@(responder.identifier().c_str())), @"identifier" : SKObject(@(responder.identifier().c_str())),
@"handler": SKObject(NSStringFromClass([actionInfo.responder class])), @"handler" :
@"selector": SKObject(NSStringFromSelector(responder.selector())), SKObject(NSStringFromClass([actionInfo.responder class])),
@"selector" :
SKObject(NSStringFromSelector(responder.selector())),
}]; }];
} }
} }
@@ -195,13 +218,17 @@ static CK::StaticMutex _mutex = CK_MUTEX_INITIALIZER;
} }
// Only add accessibility panel if accessibilityContext is not default // Only add accessibility panel if accessibilityContext is not default
CKComponentAccessibilityContext accessibilityContext = [self viewConfiguration].accessibilityContext(); CKComponentAccessibilityContext accessibilityContext =
[self viewConfiguration].accessibilityContext();
if (!AccessibilityContextIsDefault(accessibilityContext)) { if (!AccessibilityContextIsDefault(accessibilityContext)) {
[data addObject: [data addObject:[SKNamed
[SKNamed newWithName: @"Accessibility" newWithName:@"Accessibility"
withValue:@{ withValue:@{
@"accessibilityContext": AccessibilityContextDict(accessibilityContext), @"accessibilityContext" :
@"accessibilityEnabled": SKMutableObject(@(CK::Component::Accessibility::IsAccessibilityEnabled())), AccessibilityContextDict(accessibilityContext),
@"accessibilityEnabled" : SKMutableObject(
@(CK::Component::Accessibility::
IsAccessibilityEnabled())),
}]]; }]];
} }
if ([self respondsToSelector:@selector(sonar_additionalDataOverride)]) { if ([self respondsToSelector:@selector(sonar_additionalDataOverride)]) {
@@ -212,7 +239,6 @@ static CK::StaticMutex _mutex = CK_MUTEX_INITIALIZER;
} }
- (void)setMutableData:(id)value { - (void)setMutableData:(id)value {
} }
- (void)setMutableDataFromStorage { - (void)setMutableDataFromStorage {
@@ -224,24 +250,28 @@ static CK::StaticMutex _mutex = CK_MUTEX_INITIALIZER;
} }
+ (NSString*)swizzledMethodNameForRender { + (NSString*)swizzledMethodNameForRender {
return [NSString stringWithFormat:@"sonar_render_%@", NSStringFromClass(self)]; return
[NSString stringWithFormat:@"sonar_render_%@", NSStringFromClass(self)];
} }
+ (SEL)registerNewImplementation:(SEL)selector { + (SEL)registerNewImplementation:(SEL)selector {
SEL resultSelector = sel_registerName([[self swizzledMethodNameForRender] UTF8String]); SEL resultSelector =
sel_registerName([[self swizzledMethodNameForRender] UTF8String]);
Method method = class_getInstanceMethod(self, selector); Method method = class_getInstanceMethod(self, selector);
class_addMethod(self, class_addMethod(
self,
resultSelector, resultSelector,
method_getImplementation(method), method_getImplementation(method),
method_getTypeEncoding(method) method_getTypeEncoding(method));
);
return resultSelector; return resultSelector;
} }
- (CKComponent*)sonar_render:(id)state { - (CKComponent*)sonar_render:(id)state {
[self setMutableDataFromStorage]; [self setMutableDataFromStorage];
SEL resultSelector = NSSelectorFromString([[self class] swizzledMethodNameForRender]); SEL resultSelector =
return ((CKComponent *(*)(CKComponent *, SEL, id))objc_msgSend)(self, resultSelector, state); NSSelectorFromString([[self class] swizzledMethodNameForRender]);
return ((CKComponent * (*)(CKComponent*, SEL, id)) objc_msgSend)(
self, resultSelector, state);
} }
- (NSDictionary<NSString*, SKNodeDataChanged>*)sonar_getDataMutationsChanged { - (NSDictionary<NSString*, SKNodeDataChanged>*)sonar_getDataMutationsChanged {
@@ -259,14 +289,18 @@ static CK::StaticMutex _mutex = CK_MUTEX_INITIALIZER;
if (![_swizzledClasses containsObject:NSStringFromClass([self class])]) { if (![_swizzledClasses containsObject:NSStringFromClass([self class])]) {
[_swizzledClasses addObject:NSStringFromClass([self class])]; [_swizzledClasses addObject:NSStringFromClass([self class])];
if ([self respondsToSelector:@selector(render:)]) { if ([self respondsToSelector:@selector(render:)]) {
SEL replacement = [[self class] registerNewImplementation:@selector(sonar_render:)]; SEL replacement =
[[self class] registerNewImplementation:@selector(sonar_render:)];
[[self class] swizzleOriginalSEL:@selector(render:) to:replacement]; [[self class] swizzleOriginalSEL:@selector(render:) to:replacement];
} else { } else {
CKAssert(NO, @"Only CKRenderLayoutComponent and CKRenderLayoutWithChildrenComponent children are now able to be live editable"); CKAssert(
NO,
@"Only CKRenderLayoutComponent and CKRenderLayoutWithChildrenComponent children are now able to be live editable");
} }
} }
} }
NSDictionary<NSString *, SKNodeDataChanged> *dataChanged = [self sonar_getDataMutationsChanged]; NSDictionary<NSString*, SKNodeDataChanged>* dataChanged =
[self sonar_getDataMutationsChanged];
NSMutableDictionary* dataMutation = [[NSMutableDictionary alloc] init]; NSMutableDictionary* dataMutation = [[NSMutableDictionary alloc] init];
[dataMutation addEntriesFromDictionary:@{ [dataMutation addEntriesFromDictionary:@{
@"Accessibility.accessibilityEnabled": ^(NSNumber *value) { @"Accessibility.accessibilityEnabled": ^(NSNumber *value) {
@@ -277,10 +311,12 @@ static CK::StaticMutex _mutex = CK_MUTEX_INITIALIZER;
const auto globalID = self.treeNode.nodeIdentifier; const auto globalID = self.treeNode.nodeIdentifier;
for (NSString* key in dataChanged) { for (NSString* key in dataChanged) {
const auto block = dataChanged[key]; const auto block = dataChanged[key];
[dataMutation setObject:^(id value) { [dataMutation
setObject:^(id value) {
id data = block(value); id data = block(value);
[_dataStorage setData:data forTreeNodeIdentifier:globalID]; [_dataStorage setData:data forTreeNodeIdentifier:globalID];
[CKComponentDebugController reflowComponentsWithTreeNodeIdentifier:globalID]; [CKComponentDebugController
reflowComponentsWithTreeNodeIdentifier:globalID];
} }
forKey:key]; forKey:key];
} }
@@ -289,14 +325,17 @@ static CK::StaticMutex _mutex = CK_MUTEX_INITIALIZER;
static char const kCanBeReusedKey = ' '; static char const kCanBeReusedKey = ' ';
- (void)setFlipper_canBeReusedCounter:(NSUInteger)canBeReusedCounter - (void)setFlipper_canBeReusedCounter:(NSUInteger)canBeReusedCounter {
{ objc_setAssociatedObject(
objc_setAssociatedObject(self, &kCanBeReusedKey, @(canBeReusedCounter), OBJC_ASSOCIATION_RETAIN_NONATOMIC); self,
&kCanBeReusedKey,
@(canBeReusedCounter),
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
} }
- (NSUInteger)flipper_canBeReusedCounter - (NSUInteger)flipper_canBeReusedCounter {
{ return [objc_getAssociatedObject(self, &kCanBeReusedKey)
return [objc_getAssociatedObject(self, &kCanBeReusedKey) unsignedIntegerValue]; unsignedIntegerValue];
} }
@end @end

View File

@@ -28,8 +28,7 @@ static NSDictionary<NSNumber *, NSString *> *CKFlexboxAlignContentEnumMap;
static NSDictionary<NSNumber*, NSString*>* CKFlexboxWrapEnumMap; static NSDictionary<NSNumber*, NSString*>* CKFlexboxWrapEnumMap;
+ (void)initialize + (void)initialize {
{
CKFlexboxDirectionEnumMap = @{ CKFlexboxDirectionEnumMap = @{
@(CKFlexboxDirectionColumn) : @"column", @(CKFlexboxDirectionColumn) : @"column",
@(CKFlexboxDirectionRow) : @"row", @(CKFlexboxDirectionRow) : @"row",
@@ -65,8 +64,8 @@ static NSDictionary<NSNumber *, NSString *> *CKFlexboxWrapEnumMap;
}; };
} }
- (NSArray<SKNamed<NSDictionary<NSString *, NSObject *> *> *> *)sonar_additionalDataOverride - (NSArray<SKNamed<NSDictionary<NSString*, NSObject*>*>*>*)
{ sonar_additionalDataOverride {
CKFlexboxComponentStyle style; CKFlexboxComponentStyle style;
[[self valueForKey:@"_style"] getValue:&style]; [[self valueForKey:@"_style"] getValue:&style];
@@ -74,10 +73,14 @@ static NSDictionary<NSNumber *, NSString *> *CKFlexboxWrapEnumMap;
newWithName:@"CKFlexboxComponent" newWithName:@"CKFlexboxComponent"
withValue:@{ withValue:@{
@"spacing" : SKMutableObject(@(style.spacing)), @"spacing" : SKMutableObject(@(style.spacing)),
@"direction": SKMutableObject(CKFlexboxDirectionEnumMap[@(style.direction)]), @"direction" :
@"justifyContent": SKMutableObject(CKFlexboxJustifyContentEnumMap[@(style.justifyContent)]), SKMutableObject(CKFlexboxDirectionEnumMap[@(style.direction)]),
@"alignItems": SKMutableObject(CKFlexboxAlignItemsEnumMap[@(style.alignItems)]), @"justifyContent" : SKMutableObject(
@"alignContent": SKMutableObject(CKFlexboxAlignContentEnumMap[@(style.alignContent)]), CKFlexboxJustifyContentEnumMap[@(style.justifyContent)]),
@"alignItems" :
SKMutableObject(CKFlexboxAlignItemsEnumMap[@(style.alignItems)]),
@"alignContent" : SKMutableObject(
CKFlexboxAlignContentEnumMap[@(style.alignContent)]),
@"wrap" : SKMutableObject(CKFlexboxWrapEnumMap[@(style.wrap)]), @"wrap" : SKMutableObject(CKFlexboxWrapEnumMap[@(style.wrap)]),
@"padding" : SKMutableObject(flexboxRect(style.padding)), @"padding" : SKMutableObject(flexboxRect(style.padding)),
}] ]; }] ];
@@ -92,11 +95,11 @@ static NSDictionary<NSNumber *, NSString *> *CKFlexboxWrapEnumMap;
- (NSDictionary<NSString*, SKNodeDataChanged>*)sonar_getDataMutationsChanged { - (NSDictionary<NSString*, SKNodeDataChanged>*)sonar_getDataMutationsChanged {
__block CKFlexboxComponentStyle style; __block CKFlexboxComponentStyle style;
[[self valueForKey:@"_style"] getValue:&style]; [[self valueForKey:@"_style"] getValue:&style];
return @{ return @{@"CKFlexboxComponent.spacing" : ^(NSNumber* value){
@"CKFlexboxComponent.spacing": ^(NSNumber *value) {
style.spacing = value.floatValue; style.spacing = value.floatValue;
return [NSValue value:&style withObjCType:@encode(CKFlexboxComponentStyle)]; return [NSValue value:&style withObjCType:@encode(CKFlexboxComponentStyle)];
}, }
,
@"CKFlexboxComponent.direction": ^(NSString *value) { @"CKFlexboxComponent.direction": ^(NSString *value) {
for (NSNumber *key in CKFlexboxDirectionEnumMap) { for (NSNumber *key in CKFlexboxDirectionEnumMap) {
if ([CKFlexboxDirectionEnumMap[key] isEqualToString:value]) { if ([CKFlexboxDirectionEnumMap[key] isEqualToString:value]) {
@@ -158,7 +161,8 @@ static NSDictionary<NSNumber *, NSString *> *CKFlexboxWrapEnumMap;
style.padding.start = relativeStructDimension(value); style.padding.start = relativeStructDimension(value);
return [NSValue value:&style withObjCType:@encode(CKFlexboxComponentStyle)]; return [NSValue value:&style withObjCType:@encode(CKFlexboxComponentStyle)];
}, },
}; }
;
} }
@end @end

View File

@@ -17,9 +17,13 @@
FB_LINKABLE(CKInsetComponent_Sonar) FB_LINKABLE(CKInsetComponent_Sonar)
@implementation CKInsetComponent (Sonar) @implementation CKInsetComponent (Sonar)
- (NSArray<SKNamed<NSDictionary<NSString *, NSObject *> *> *> *)sonar_additionalDataOverride - (NSArray<SKNamed<NSDictionary<NSString*, NSObject*>*>*>*)
{ sonar_additionalDataOverride {
return @[[SKNamed newWithName:@"CKInsetComponent" withValue:@{@"insets": SKMutableObject([[self valueForKey:@"_insets"] UIEdgeInsetsValue])}]]; return @[ [SKNamed newWithName:@"CKInsetComponent"
withValue:@{
@"insets" : SKMutableObject(
[[self valueForKey:@"_insets"] UIEdgeInsetsValue])
}] ];
} }
- (void)setMutableData:(id)data { - (void)setMutableData:(id)data {
@@ -27,12 +31,13 @@ FB_LINKABLE(CKInsetComponent_Sonar)
} }
- (NSDictionary<NSString*, SKNodeDataChanged>*)sonar_getDataMutationsChanged { - (NSDictionary<NSString*, SKNodeDataChanged>*)sonar_getDataMutationsChanged {
__block UIEdgeInsets insets = [[self valueForKey:@"_insets"] UIEdgeInsetsValue]; __block UIEdgeInsets insets =
return @{ [[self valueForKey:@"_insets"] UIEdgeInsetsValue];
@"CKInsetComponent.insets.bottom": ^(NSNumber *value) { return @{@"CKInsetComponent.insets.bottom" : ^(NSNumber* value){
insets.bottom = value.floatValue; insets.bottom = value.floatValue;
return [NSValue valueWithUIEdgeInsets:insets]; return [NSValue valueWithUIEdgeInsets:insets];
}, }
,
@"CKInsetComponent.insets.left": ^(NSNumber *value) { @"CKInsetComponent.insets.left": ^(NSNumber *value) {
insets.left = value.floatValue; insets.left = value.floatValue;
return [NSValue valueWithUIEdgeInsets:insets]; return [NSValue valueWithUIEdgeInsets:insets];
@@ -45,7 +50,8 @@ FB_LINKABLE(CKInsetComponent_Sonar)
insets.top = value.floatValue; insets.top = value.floatValue;
return [NSValue valueWithUIEdgeInsets:insets]; return [NSValue valueWithUIEdgeInsets:insets];
}, },
}; }
;
} }
@end @end

View File

@@ -12,4 +12,3 @@ FB_LINK_REQUIRE_CATEGORY(CKRatioLayoutComponent_Sonar)
@interface CKRatioLayoutComponent (Sonar) @interface CKRatioLayoutComponent (Sonar)
@end @end

View File

@@ -17,9 +17,13 @@
FB_LINKABLE(CKRatioLayoutComponent_Sonar) FB_LINKABLE(CKRatioLayoutComponent_Sonar)
@implementation CKRatioLayoutComponent (Sonar) @implementation CKRatioLayoutComponent (Sonar)
- (NSArray<SKNamed<NSDictionary<NSString *, NSObject *> *> *> *)sonar_additionalDataOverride - (NSArray<SKNamed<NSDictionary<NSString*, NSObject*>*>*>*)
{ sonar_additionalDataOverride {
return @[[SKNamed newWithName:@"CKRatioLayoutComponent" withValue:@{@"ratio": SKMutableObject((NSNumber *)[self valueForKey:@"_ratio"])}]]; return @[ [SKNamed
newWithName:@"CKRatioLayoutComponent"
withValue:@{
@"ratio" : SKMutableObject((NSNumber*)[self valueForKey:@"_ratio"])
}] ];
} }
- (void)setMutableData:(id)data { - (void)setMutableData:(id)data {
@@ -27,13 +31,14 @@ FB_LINKABLE(CKRatioLayoutComponent_Sonar)
} }
- (NSDictionary<NSString*, SKNodeDataChanged>*)sonar_getDataMutationsChanged { - (NSDictionary<NSString*, SKNodeDataChanged>*)sonar_getDataMutationsChanged {
return @{ return @{@"CKRatioLayoutComponent.ratio" : ^(NSNumber* value){
@"CKRatioLayoutComponent.ratio": ^(NSNumber *value) {
CGFloat ratio = [(NSNumber*)[self valueForKey:@"_ratio"] floatValue]; CGFloat ratio = [(NSNumber*)[self valueForKey:@"_ratio"] floatValue];
ratio = value.floatValue; ratio = value.floatValue;
return [NSNumber numberWithFloat:ratio]; return [NSNumber numberWithFloat:ratio];
}, }
}; ,
}
;
} }
@end @end

View File

@@ -17,8 +17,7 @@
FB_LINKABLE(CKStatelessComponent_Sonar) FB_LINKABLE(CKStatelessComponent_Sonar)
@implementation CKStatelessComponent (Sonar) @implementation CKStatelessComponent (Sonar)
- (NSString *)sonar_componentNameOverride - (NSString*)sonar_componentNameOverride {
{
return [self description]; return [self description];
} }

View File

@@ -12,6 +12,7 @@ to prodice live editing*/
@interface FKDataStorageForLiveEditing : NSObject @interface FKDataStorageForLiveEditing : NSObject
- (id)dataForTreeNodeIdentifier:(CKTreeNodeIdentifier)treeNodeIdentifier; - (id)dataForTreeNodeIdentifier:(CKTreeNodeIdentifier)treeNodeIdentifier;
- (void)setData:(id)value forTreeNodeIdentifier:(CKTreeNodeIdentifier)treeNodeIdentifier; - (void)setData:(id)value
forTreeNodeIdentifier:(CKTreeNodeIdentifier)treeNodeIdentifier;
@end @end

View File

@@ -14,7 +14,8 @@
std::mutex _mutex; std::mutex _mutex;
} }
- (void)setData:(id)value forTreeNodeIdentifier:(CKTreeNodeIdentifier)treeNodeIdentifier { - (void)setData:(id)value
forTreeNodeIdentifier:(CKTreeNodeIdentifier)treeNodeIdentifier {
std::lock_guard<std::mutex> lock(_mutex); std::lock_guard<std::mutex> lock(_mutex);
_data[treeNodeIdentifier] = value; _data[treeNodeIdentifier] = value;
} }

View File

@@ -7,8 +7,8 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "SKSubDescriptor.h"
#import <FlipperKitLayoutPlugin/SKDescriptorMapper.h> #import <FlipperKitLayoutPlugin/SKDescriptorMapper.h>
#import "SKSubDescriptor.h"
@interface FlipperKitLayoutComponentKitSupport : NSObject @interface FlipperKitLayoutComponentKitSupport : NSObject

View File

@@ -9,42 +9,48 @@
#import "FlipperKitLayoutComponentKitSupport.h" #import "FlipperKitLayoutComponentKitSupport.h"
#import <ComponentKit/CKComponentRootView.h>
#import <ComponentKit/CKComponentHostingView.h> #import <ComponentKit/CKComponentHostingView.h>
#import <ComponentKit/CKComponentRootView.h>
#import <FlipperKitLayoutPlugin/SKDescriptorMapper.h> #import <FlipperKitLayoutPlugin/SKDescriptorMapper.h>
#import "SKComponentHostingViewDescriptor.h" #import "SKComponentHostingViewDescriptor.h"
#import "SKComponentRootViewDescriptor.h"
#import "SKComponentLayoutDescriptor.h" #import "SKComponentLayoutDescriptor.h"
#import "SKComponentLayoutWrapper.h" #import "SKComponentLayoutWrapper.h"
#import "SKComponentRootViewDescriptor.h"
#import "SKSubDescriptor.h" #import "SKSubDescriptor.h"
@implementation FlipperKitLayoutComponentKitSupport @implementation FlipperKitLayoutComponentKitSupport
+ (void)setUpWithDescriptorMapper:(SKDescriptorMapper*)mapper + (void)setUpWithDescriptorMapper:(SKDescriptorMapper*)mapper
subDescriptors:(NSArray<SKSubDescriptor*>*)subDescriptors { subDescriptors:(NSArray<SKSubDescriptor*>*)subDescriptors {
[mapper registerDescriptor: [[SKComponentHostingViewDescriptor alloc] initWithDescriptorMapper: mapper] [mapper registerDescriptor:[[SKComponentHostingViewDescriptor alloc]
initWithDescriptorMapper:mapper]
forClass:[CKComponentHostingView class]]; forClass:[CKComponentHostingView class]];
[mapper registerDescriptor: [[SKComponentRootViewDescriptor alloc] initWithDescriptorMapper: mapper] [mapper registerDescriptor:[[SKComponentRootViewDescriptor alloc]
initWithDescriptorMapper:mapper]
forClass:[CKComponentRootView class]]; forClass:[CKComponentRootView class]];
SKComponentLayoutDescriptor *layoutDescriptor = [[SKComponentLayoutDescriptor alloc] initWithDescriptorMapper:mapper]; SKComponentLayoutDescriptor* layoutDescriptor =
[[SKComponentLayoutDescriptor alloc] initWithDescriptorMapper:mapper];
[layoutDescriptor addSubDescriptors:subDescriptors]; [layoutDescriptor addSubDescriptors:subDescriptors];
[mapper registerDescriptor:layoutDescriptor [mapper registerDescriptor:layoutDescriptor
forClass:[SKComponentLayoutWrapper class]]; forClass:[SKComponentLayoutWrapper class]];
} }
+ (void)setUpWithDescriptorMapper:(SKDescriptorMapper*)mapper { + (void)setUpWithDescriptorMapper:(SKDescriptorMapper*)mapper {
// What we really want here is "forProtocol:@protocol(CKInspectableView)" but no such luck. // What we really want here is "forProtocol:@protocol(CKInspectableView)" but
[mapper registerDescriptor: [[SKComponentHostingViewDescriptor alloc] initWithDescriptorMapper: mapper] // no such luck.
[mapper registerDescriptor:[[SKComponentHostingViewDescriptor alloc]
initWithDescriptorMapper:mapper]
forClass:[CKComponentHostingView class]]; forClass:[CKComponentHostingView class]];
[mapper registerDescriptor: [[SKComponentRootViewDescriptor alloc] initWithDescriptorMapper: mapper] [mapper registerDescriptor:[[SKComponentRootViewDescriptor alloc]
initWithDescriptorMapper:mapper]
forClass:[CKComponentRootView class]]; forClass:[CKComponentRootView class]];
[mapper registerDescriptor: [[SKComponentLayoutDescriptor alloc] initWithDescriptorMapper: mapper] [mapper registerDescriptor:[[SKComponentLayoutDescriptor alloc]
initWithDescriptorMapper:mapper]
forClass:[SKComponentLayoutWrapper class]]; forClass:[SKComponentLayoutWrapper class]];
} }
@end @end
#endif #endif

View File

@@ -9,6 +9,7 @@
@class CKComponentHostingView; @class CKComponentHostingView;
@interface SKComponentHostingViewDescriptor : SKNodeDescriptor<CKComponentHostingView *> @interface SKComponentHostingViewDescriptor
: SKNodeDescriptor<CKComponentHostingView*>
@end @end

View File

@@ -13,7 +13,6 @@
#import <ComponentKit/CKComponentHostingView.h> #import <ComponentKit/CKComponentHostingView.h>
#import <ComponentKit/CKComponentHostingViewInternal.h> #import <ComponentKit/CKComponentHostingViewInternal.h>
#import <ComponentKit/CKComponentLayout.h> #import <ComponentKit/CKComponentLayout.h>
#import <ComponentKit/CKComponentHostingViewInternal.h>
#import <FlipperKitLayoutPlugin/SKDescriptorMapper.h> #import <FlipperKitLayoutPlugin/SKDescriptorMapper.h>

View File

@@ -11,7 +11,8 @@
@class SKComponentLayoutWrapper; @class SKComponentLayoutWrapper;
@interface SKComponentLayoutDescriptor: SKNodeDescriptor<SKComponentLayoutWrapper *> @interface SKComponentLayoutDescriptor
: SKNodeDescriptor<SKComponentLayoutWrapper*>
- (void)addSubDescriptors:(NSArray<SKSubDescriptor*>*)subDescriptors; - (void)addSubDescriptors:(NSArray<SKSubDescriptor*>*)subDescriptors;

View File

@@ -10,27 +10,26 @@
#import "SKComponentLayoutDescriptor.h" #import "SKComponentLayoutDescriptor.h"
#import <ComponentKit/CKComponent.h> #import <ComponentKit/CKComponent.h>
#import <ComponentKit/CKComponentInternal.h> #import <ComponentKit/CKComponentAccessibility.h>
#import <ComponentKit/CKComponentActionInternal.h> #import <ComponentKit/CKComponentActionInternal.h>
#import <ComponentKit/CKComponentDebugController.h>
#import <ComponentKit/CKComponentInternal.h>
#import <ComponentKit/CKComponentLayout.h> #import <ComponentKit/CKComponentLayout.h>
#import <ComponentKit/CKComponentRootView.h> #import <ComponentKit/CKComponentRootView.h>
#import <ComponentKit/CKComponentViewConfiguration.h> #import <ComponentKit/CKComponentViewConfiguration.h>
#import <ComponentKit/CKComponentAccessibility.h>
#import <ComponentKit/CKComponentDebugController.h>
#import <ComponentKit/CKInsetComponent.h>
#import <ComponentKit/CKFlexboxComponent.h> #import <ComponentKit/CKFlexboxComponent.h>
#import <ComponentKit/CKInsetComponent.h>
#import <FlipperKitHighlightOverlay/SKHighlightOverlay.h> #import <FlipperKitHighlightOverlay/SKHighlightOverlay.h>
#import <FlipperKitLayoutPlugin/SKObject.h> #import <FlipperKitLayoutPlugin/SKObject.h>
#import <FlipperKitLayoutTextSearchable/FKTextSearchable.h> #import <FlipperKitLayoutTextSearchable/FKTextSearchable.h>
#import "SKSubDescriptor.h"
#import "SKComponentLayoutWrapper.h"
#import "CKComponent+Sonar.h" #import "CKComponent+Sonar.h"
#import "SKComponentLayoutWrapper.h"
#import "SKSubDescriptor.h"
#import "Utils.h" #import "Utils.h"
@implementation SKComponentLayoutDescriptor @implementation SKComponentLayoutDescriptor {
{
NSDictionary<NSNumber*, NSString*>* CKFlexboxAlignSelfEnumMap; NSDictionary<NSNumber*, NSString*>* CKFlexboxAlignSelfEnumMap;
NSDictionary<NSNumber*, NSString*>* CKFlexboxPositionTypeEnumMap; NSDictionary<NSNumber*, NSString*>* CKFlexboxPositionTypeEnumMap;
NSArray<SKSubDescriptor*>* _registeredSubdescriptors; NSArray<SKSubDescriptor*>* _registeredSubdescriptors;
@@ -69,8 +68,7 @@
return node.identifier; return node.identifier;
} }
- (NSString *)identifierForInvalidation:(SKComponentLayoutWrapper *)node - (NSString*)identifierForInvalidation:(SKComponentLayoutWrapper*)node {
{
return [NSString stringWithFormat:@"%p", node.rootNode]; return [NSString stringWithFormat:@"%p", node.rootNode];
} }
@@ -100,19 +98,27 @@
return node.children[index]; return node.children[index];
} }
- (NSArray<SKNamed<NSDictionary<NSString *, NSObject *> *> *> *)dataForNode:(SKComponentLayoutWrapper *)node { - (NSArray<SKNamed<NSDictionary<NSString*, NSObject*>*>*>*)dataForNode:
NSMutableArray<SKNamed<NSDictionary<NSString *, NSObject *> *> *> *data = [NSMutableArray new]; (SKComponentLayoutWrapper*)node {
NSMutableArray<SKNamed<NSDictionary<NSString*, NSObject*>*>*>* data =
[NSMutableArray new];
if (node.isFlexboxChild) { if (node.isFlexboxChild) {
[data addObject: [SKNamed newWithName:@"Layout" withValue:[self propsForFlexboxChild:node.flexboxChild]]]; [data
addObject:[SKNamed
newWithName:@"Layout"
withValue:[self
propsForFlexboxChild:node.flexboxChild]]];
} }
NSMutableDictionary<NSString *, NSObject *> *extraData = [[NSMutableDictionary alloc] init]; NSMutableDictionary<NSString*, NSObject*>* extraData =
[[NSMutableDictionary alloc] init];
for (SKSubDescriptor* s in _registeredSubdescriptors) { for (SKSubDescriptor* s in _registeredSubdescriptors) {
[extraData setObject:[s getDataForNode:node] forKey:[s getName]]; [extraData setObject:[s getDataForNode:node] forKey:[s getName]];
} }
if (extraData.count > 0) { if (extraData.count > 0) {
[data addObject: [SKNamed newWithName:@"Extra Sections" withValue:extraData]]; [data addObject:[SKNamed newWithName:@"Extra Sections"
withValue:extraData]];
} }
[data addObjectsFromArray:[node.component sonar_getData]]; [data addObjectsFromArray:[node.component sonar_getData]];
@@ -123,7 +129,8 @@
_registeredSubdescriptors = subDescriptors; _registeredSubdescriptors = subDescriptors;
} }
- (NSDictionary<NSString *, NSObject *> *)propsForFlexboxChild:(CKFlexboxComponentChild)child { - (NSDictionary<NSString*, NSObject*>*)propsForFlexboxChild:
(CKFlexboxComponentChild)child {
return @{ return @{
@"spacingBefore" : SKObject(@(child.spacingBefore)), @"spacingBefore" : SKObject(@(child.spacingBefore)),
@"spacingAfter" : SKObject(@(child.spacingAfter)), @"spacingAfter" : SKObject(@(child.spacingAfter)),
@@ -149,23 +156,28 @@
}; };
} }
- (NSDictionary<NSString *, SKNodeUpdateData> *)dataMutationsForNode:(SKComponentLayoutWrapper *)node { - (NSDictionary<NSString*, SKNodeUpdateData>*)dataMutationsForNode:
(SKComponentLayoutWrapper*)node {
return [node.component sonar_getDataMutations]; return [node.component sonar_getDataMutations];
} }
- (NSArray<SKNamed<NSString *> *> *)attributesForNode:(SKComponentLayoutWrapper *)node { - (NSArray<SKNamed<NSString*>*>*)attributesForNode:
(SKComponentLayoutWrapper*)node {
NSMutableArray<SKNamed<NSString*>*>* attributes = [NSMutableArray array]; NSMutableArray<SKNamed<NSString*>*>* attributes = [NSMutableArray array];
[attributes addObject:[SKNamed newWithName:@"responder" [attributes
withValue:SKObject(NSStringFromClass([node.component.nextResponder class]))]]; addObject:[SKNamed
newWithName:@"responder"
withValue:SKObject(NSStringFromClass(
[node.component.nextResponder class]))]];
return attributes; return attributes;
} }
- (void)setHighlighted:(BOOL)highlighted forNode:(SKComponentLayoutWrapper *)node { - (void)setHighlighted:(BOOL)highlighted
forNode:(SKComponentLayoutWrapper*)node {
SKHighlightOverlay* overlay = [SKHighlightOverlay sharedInstance]; SKHighlightOverlay* overlay = [SKHighlightOverlay sharedInstance];
if (highlighted) { if (highlighted) {
CKComponentViewContext viewContext = node.component.viewContext; CKComponentViewContext viewContext = node.component.viewContext;
[overlay mountInView: viewContext.view [overlay mountInView:viewContext.view withFrame:viewContext.frame];
withFrame: viewContext.frame];
} else { } else {
[overlay unmount]; [overlay unmount];
} }
@@ -186,10 +198,7 @@
for (index = node.children.size() - 1; index >= 0; index--) { for (index = node.children.size() - 1; index >= 0; index--) {
const auto child = node.children[index]; const auto child = node.children[index];
CGRect frame = { CGRect frame = {.origin = child.position, .size = child.size};
.origin = child.position,
.size = child.size
};
if ([touch containedIn:frame]) { if ([touch containedIn:frame]) {
[touch continueWithChildIndex:index withOffset:child.position]; [touch continueWithChildIndex:index withOffset:child.position];
@@ -206,8 +215,10 @@
} }
if ([node isKindOfClass:[SKComponentLayoutWrapper class]]) { if ([node isKindOfClass:[SKComponentLayoutWrapper class]]) {
const auto layoutWrapper = (SKComponentLayoutWrapper*)node; const auto layoutWrapper = (SKComponentLayoutWrapper*)node;
if ([layoutWrapper.component conformsToProtocol:@protocol(FKTextSearchable)]) { if ([layoutWrapper.component
NSString *text = ((id<FKTextSearchable>)layoutWrapper.component).searchableText; conformsToProtocol:@protocol(FKTextSearchable)]) {
NSString* text =
((id<FKTextSearchable>)layoutWrapper.component).searchableText;
return [self string:text contains:query]; return [self string:text contains:query];
} }
} }
@@ -215,7 +226,9 @@
} }
- (BOOL)string:(NSString*)string contains:(NSString*)substring { - (BOOL)string:(NSString*)string contains:(NSString*)substring {
return string != nil && substring != nil && [string rangeOfString: substring options: NSCaseInsensitiveSearch].location != NSNotFound; return string != nil && substring != nil &&
[string rangeOfString:substring options:NSCaseInsensitiveSearch]
.location != NSNotFound;
} }
@end @end

View File

@@ -25,6 +25,7 @@
@property(nonatomic, readonly) CKFlexboxComponentChild flexboxChild; @property(nonatomic, readonly) CKFlexboxComponentChild flexboxChild;
+ (instancetype)newFromRoot:(id<CKInspectableView>)root; + (instancetype)newFromRoot:(id<CKInspectableView>)root;
+ (instancetype)newFromRoot:(id<CKInspectableView>)root parentKey:(NSString *)parentKey; + (instancetype)newFromRoot:(id<CKInspectableView>)root
parentKey:(NSString*)parentKey;
@end @end

View File

@@ -11,23 +11,27 @@
#import <ComponentKit/CKAnalyticsListenerHelpers.h> #import <ComponentKit/CKAnalyticsListenerHelpers.h>
#import <ComponentKit/CKComponent.h> #import <ComponentKit/CKComponent.h>
#import <ComponentKit/CKComponentInternal.h>
#import <ComponentKit/CKComponentRootView.h>
#import <ComponentKit/CKComponentAttachController.h> #import <ComponentKit/CKComponentAttachController.h>
#import <ComponentKit/CKComponentAttachControllerInternal.h> #import <ComponentKit/CKComponentAttachControllerInternal.h>
#import <ComponentKit/CKComponentInternal.h>
#import <ComponentKit/CKComponentRootView.h>
#import <ComponentKit/CKInspectableView.h> #import <ComponentKit/CKInspectableView.h>
#import "CKComponent+Sonar.h" #import "CKComponent+Sonar.h"
static char const kLayoutWrapperKey = ' '; static char const kLayoutWrapperKey = ' ';
static CKFlexboxComponentChild findFlexboxLayoutParams(CKComponent *parent, CKComponent *child) { static CKFlexboxComponentChild findFlexboxLayoutParams(
CKComponent* parent,
CKComponent* child) {
if ([parent isKindOfClass:[CKFlexboxComponent class]]) { if ([parent isKindOfClass:[CKFlexboxComponent class]]) {
static Ivar ivar = class_getInstanceVariable([CKFlexboxComponent class], "_children"); static Ivar ivar =
class_getInstanceVariable([CKFlexboxComponent class], "_children");
static ptrdiff_t offset = ivar_getOffset(ivar); static ptrdiff_t offset = ivar_getOffset(ivar);
unsigned char* pComponent = (unsigned char*)(__bridge void*)parent; unsigned char* pComponent = (unsigned char*)(__bridge void*)parent;
auto children = (std::vector<CKFlexboxComponentChild> *)(pComponent + offset); auto children =
(std::vector<CKFlexboxComponentChild>*)(pComponent + offset);
if (children) { if (children) {
for (auto it = children->begin(); it != children->end(); it++) { for (auto it = children->begin(); it != children->end(); it++) {
@@ -47,28 +51,38 @@ static CKFlexboxComponentChild findFlexboxLayoutParams(CKComponent *parent, CKCo
return [self newFromRoot:root parentKey:@""]; return [self newFromRoot:root parentKey:@""];
} }
+ (instancetype)newFromRoot:(id<CKInspectableView>)root parentKey:(NSString *)parentKey { + (instancetype)newFromRoot:(id<CKInspectableView>)root
parentKey:(NSString*)parentKey {
const CKComponentLayout layout = [root mountedLayout]; const CKComponentLayout layout = [root mountedLayout];
// Check if there is a cached wrapper. // Check if there is a cached wrapper.
if (layout.component) { if (layout.component) {
SKComponentLayoutWrapper *cachedWrapper = objc_getAssociatedObject(layout.component, &kLayoutWrapperKey); SKComponentLayoutWrapper* cachedWrapper =
objc_getAssociatedObject(layout.component, &kLayoutWrapperKey);
if (cachedWrapper) { if (cachedWrapper) {
return cachedWrapper; return cachedWrapper;
} }
} }
// TODO: Add support for `CKMountable` components. // TODO: Add support for `CKMountable` components.
CKComponent* component = (CKComponent*)layout.component; CKComponent* component = (CKComponent*)layout.component;
CKComponentReuseWrapper *reuseWrapper = CKAnalyticsListenerHelpers::GetReusedNodes(component); CKComponentReuseWrapper* reuseWrapper =
CKAnalyticsListenerHelpers::GetReusedNodes(component);
// Create a new layout wrapper. // Create a new layout wrapper.
SKComponentLayoutWrapper *const wrapper = SKComponentLayoutWrapper* const wrapper = [[SKComponentLayoutWrapper alloc]
[[SKComponentLayoutWrapper alloc] initWithLayout:layout initWithLayout:layout
position:CGPointMake(0, 0) position:CGPointMake(0, 0)
parentKey:[NSString stringWithFormat: @"%@%d.", parentKey, component.treeNode.nodeIdentifier] parentKey:[NSString
stringWithFormat:@"%@%d.",
parentKey,
component.treeNode.nodeIdentifier]
reuseWrapper:reuseWrapper reuseWrapper:reuseWrapper
rootNode:root]; rootNode:root];
// Cache the result. // Cache the result.
if (component) { if (component) {
objc_setAssociatedObject(component, &kLayoutWrapperKey, wrapper, OBJC_ASSOCIATION_RETAIN_NONATOMIC); objc_setAssociatedObject(
component,
&kLayoutWrapperKey,
wrapper,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
} }
return wrapper; return wrapper;
} }
@@ -77,17 +91,19 @@ static CKFlexboxComponentChild findFlexboxLayoutParams(CKComponent *parent, CKCo
position:(CGPoint)position position:(CGPoint)position
parentKey:(NSString*)parentKey parentKey:(NSString*)parentKey
reuseWrapper:(CKComponentReuseWrapper*)reuseWrapper reuseWrapper:(CKComponentReuseWrapper*)reuseWrapper
rootNode:(id<CKInspectableView>)node rootNode:(id<CKInspectableView>)node {
{
if (self = [super init]) { if (self = [super init]) {
_rootNode = node; _rootNode = node;
_component = (CKComponent*)layout.component; _component = (CKComponent*)layout.component;
_size = layout.size; _size = layout.size;
_position = position; _position = position;
_identifier = [parentKey stringByAppendingString:layout.component ? NSStringFromClass([layout.component class]) : @"(null)"]; _identifier = [parentKey stringByAppendingString:layout.component
? NSStringFromClass([layout.component class])
: @"(null)"];
if (_component && reuseWrapper) { if (_component && reuseWrapper) {
auto const canBeReusedCounter = [reuseWrapper canBeReusedCounter:_component.treeNode.nodeIdentifier]; auto const canBeReusedCounter =
[reuseWrapper canBeReusedCounter:_component.treeNode.nodeIdentifier];
if (canBeReusedCounter > 0) { if (canBeReusedCounter > 0) {
_component.flipper_canBeReusedCounter = canBeReusedCounter; _component.flipper_canBeReusedCounter = canBeReusedCounter;
} }
@@ -99,14 +115,18 @@ static CKFlexboxComponentChild findFlexboxLayoutParams(CKComponent *parent, CKCo
if (child.layout.component == nil) { if (child.layout.component == nil) {
continue; // nil children are allowed, ignore them continue; // nil children are allowed, ignore them
} }
SKComponentLayoutWrapper *childWrapper = [[SKComponentLayoutWrapper alloc] initWithLayout:child.layout SKComponentLayoutWrapper* childWrapper =
[[SKComponentLayoutWrapper alloc]
initWithLayout:child.layout
position:child.position position:child.position
parentKey:[_identifier stringByAppendingFormat:@"[%d].", index++] parentKey:[_identifier
stringByAppendingFormat:@"[%d].", index++]
reuseWrapper:reuseWrapper reuseWrapper:reuseWrapper
rootNode:node rootNode:node];
]; childWrapper->_isFlexboxChild =
childWrapper->_isFlexboxChild = [_component isKindOfClass:[CKFlexboxComponent class]]; [_component isKindOfClass:[CKFlexboxComponent class]];
childWrapper->_flexboxChild = findFlexboxLayoutParams(_component, (CKComponent *)child.layout.component); childWrapper->_flexboxChild = findFlexboxLayoutParams(
_component, (CKComponent*)child.layout.component);
_children.push_back(childWrapper); _children.push_back(childWrapper);
} }
} }

View File

@@ -9,6 +9,7 @@
@class CKComponentRootView; @class CKComponentRootView;
@interface SKComponentRootViewDescriptor : SKNodeDescriptor<CKComponentRootView *> @interface SKComponentRootViewDescriptor
: SKNodeDescriptor<CKComponentRootView*>
@end @end

View File

@@ -33,8 +33,10 @@
- (id)childForNode:(CKComponentRootView*)node atIndex:(NSUInteger)index { - (id)childForNode:(CKComponentRootView*)node atIndex:(NSUInteger)index {
auto const attachState = CKGetAttachStateForView(node); auto const attachState = CKGetAttachStateForView(node);
return [SKComponentLayoutWrapper newFromRoot:node return [SKComponentLayoutWrapper
parentKey:[NSString stringWithFormat:@"%d.", attachState.scopeIdentifier]]; newFromRoot:node
parentKey:[NSString
stringWithFormat:@"%d.", attachState.scopeIdentifier]];
} }
- (void)setHighlighted:(BOOL)highlighted forNode:(CKComponentRootView*)node { - (void)setHighlighted:(BOOL)highlighted forNode:(CKComponentRootView*)node {

View File

@@ -11,8 +11,8 @@
/** /**
A SKSubDescriptor is an object which knows how to expose an Object of type T A SKSubDescriptor is an object which knows how to expose an Object of type T
to the SKLayoutDescriptor. This class is for frameworks wanting to pass data along to the SKLayoutDescriptor. This class is for frameworks wanting to pass data
through the Layout Descriptor. along through the Layout Descriptor.
*/ */
@interface SKSubDescriptor : NSObject @interface SKSubDescriptor : NSObject

View File

@@ -10,11 +10,11 @@
#import "SKSubDescriptor.h" #import "SKSubDescriptor.h"
#import "SKComponentLayoutWrapper.h" #import "SKComponentLayoutWrapper.h"
@implementation SKSubDescriptor @implementation SKSubDescriptor {
{
} }
- (NSDictionary<NSString *, NSObject *> *)getDataForNode:(SKComponentLayoutWrapper *)node { - (NSDictionary<NSString*, NSObject*>*)getDataForNode:
(SKComponentLayoutWrapper*)node {
return @{}; return @{};
} }

View File

@@ -22,10 +22,12 @@ NSString *relativeDimension(CKRelativeDimension dimension) {
CKRelativeDimension relativeStructDimension(NSString* dimension) { CKRelativeDimension relativeStructDimension(NSString* dimension) {
if ([dimension hasSuffix:@"%"]) { if ([dimension hasSuffix:@"%"]) {
return CKRelativeDimension::Percent([[dimension substringToIndex:([dimension length] - 1)] integerValue]); return CKRelativeDimension::Percent(
[[dimension substringToIndex:([dimension length] - 1)] integerValue]);
} }
if ([dimension hasSuffix:@"pt"]) { if ([dimension hasSuffix:@"pt"]) {
return CKRelativeDimension::Points([[dimension substringToIndex:([dimension length] - 2)] integerValue]); return CKRelativeDimension::Points(
[[dimension substringToIndex:([dimension length] - 2)] integerValue]);
} }
return CKRelativeDimension::Auto(); return CKRelativeDimension::Auto();
} }

View File

@@ -11,11 +11,12 @@
#import <FlipperKit/FlipperPlugin.h> #import <FlipperKit/FlipperPlugin.h>
#import "SKTapListener.h"
#import "SKInvalidation.h"
#import "SKDescriptorMapper.h" #import "SKDescriptorMapper.h"
#import "SKInvalidation.h"
#import "SKTapListener.h"
@interface FlipperKitLayoutPlugin : NSObject<FlipperPlugin, SKInvalidationDelegate> @interface FlipperKitLayoutPlugin
: NSObject<FlipperPlugin, SKInvalidationDelegate>
- (instancetype)initWithRootNode:(id<NSObject>)rootNode - (instancetype)initWithRootNode:(id<NSObject>)rootNode
withDescriptorMapper:(SKDescriptorMapper*)mapper; withDescriptorMapper:(SKDescriptorMapper*)mapper;

View File

@@ -13,16 +13,14 @@
#import <FlipperKit/FlipperConnection.h> #import <FlipperKit/FlipperConnection.h>
#import <FlipperKit/FlipperResponder.h> #import <FlipperKit/FlipperResponder.h>
#import <FlipperKit/SKMacros.h> #import <FlipperKit/SKMacros.h>
#import <mutex>
#import "SKDescriptorMapper.h" #import "SKDescriptorMapper.h"
#import "SKNodeDescriptor.h" #import "SKNodeDescriptor.h"
#import "SKSearchResultNode.h"
#import "SKTapListener.h" #import "SKTapListener.h"
#import "SKTapListenerImpl.h" #import "SKTapListenerImpl.h"
#import "SKSearchResultNode.h"
#import <mutex>
@implementation FlipperKitLayoutPlugin
{
@implementation FlipperKitLayoutPlugin {
NSMapTable<NSString*, id>* _trackedObjects; NSMapTable<NSString*, id>* _trackedObjects;
NSString* _lastHighlightedNode; NSString* _lastHighlightedNode;
NSMutableSet* _invalidObjects; NSMutableSet* _invalidObjects;
@@ -65,8 +63,7 @@
return self; return self;
} }
- (NSString *)identifier - (NSString*)identifier {
{
return @"Inspector"; return @"Inspector";
} }
@@ -85,48 +82,97 @@
[descriptor setUp]; [descriptor setUp];
} }
// In order to avoid a retain cycle (Connection -> Block -> FlipperKitLayoutPlugin -> Connection ...) // In order to avoid a retain cycle (Connection -> Block ->
// FlipperKitLayoutPlugin -> Connection ...)
__weak FlipperKitLayoutPlugin* weakSelf = self; __weak FlipperKitLayoutPlugin* weakSelf = self;
[connection receive:@"getRoot" withBlock:^(NSDictionary *params, id<FlipperResponder> responder) { [connection receive:@"getRoot"
FlipperPerformBlockOnMainThread(^{ [weakSelf onCallGetRoot: responder]; }, responder); withBlock:^(NSDictionary* params, id<FlipperResponder> responder) {
FlipperPerformBlockOnMainThread(
^{
[weakSelf onCallGetRoot:responder];
},
responder);
}]; }];
[connection receive:@"getAllNodes" withBlock:^(NSDictionary *params, id<FlipperResponder> responder) { [connection receive:@"getAllNodes"
FlipperPerformBlockOnMainThread(^{ [weakSelf onCallGetAllNodesWithResponder: responder]; }, responder); withBlock:^(NSDictionary* params, id<FlipperResponder> responder) {
FlipperPerformBlockOnMainThread(
^{
[weakSelf onCallGetAllNodesWithResponder:responder];
},
responder);
}]; }];
[connection receive:@"getNodes" withBlock:^(NSDictionary *params, id<FlipperResponder> responder) { [connection receive:@"getNodes"
FlipperPerformBlockOnMainThread(^{ [weakSelf onCallGetNodes: params[@"ids"] withResponder: responder]; }, responder); withBlock:^(NSDictionary* params, id<FlipperResponder> responder) {
FlipperPerformBlockOnMainThread(
^{
[weakSelf onCallGetNodes:params[@"ids"]
withResponder:responder];
},
responder);
}]; }];
[connection receive:@"setData" withBlock:^(NSDictionary *params, id<FlipperResponder> responder) { [connection receive:@"setData"
FlipperPerformBlockOnMainThread(^{ withBlock:^(NSDictionary* params, id<FlipperResponder> responder) {
FlipperPerformBlockOnMainThread(
^{
[weakSelf onCallSetData:params[@"id"] [weakSelf onCallSetData:params[@"id"]
withPath:params[@"path"] withPath:params[@"path"]
toValue:params[@"value"] toValue:params[@"value"]
withConnection:connection]; withConnection:connection];
}, responder); },
responder);
}]; }];
[connection receive:@"setHighlighted" withBlock:^(NSDictionary *params, id<FlipperResponder> responder) { [connection receive:@"setHighlighted"
FlipperPerformBlockOnMainThread(^{ [weakSelf onCallSetHighlighted: params[@"id"] withResponder: responder]; }, responder); withBlock:^(NSDictionary* params, id<FlipperResponder> responder) {
FlipperPerformBlockOnMainThread(
^{
[weakSelf onCallSetHighlighted:params[@"id"]
withResponder:responder];
},
responder);
}]; }];
[connection receive:@"setSearchActive" withBlock:^(NSDictionary *params, id<FlipperResponder> responder) { [connection receive:@"setSearchActive"
FlipperPerformBlockOnMainThread(^{ [weakSelf onCallSetSearchActive: [params[@"active"] boolValue] withConnection: connection]; }, responder); withBlock:^(NSDictionary* params, id<FlipperResponder> responder) {
FlipperPerformBlockOnMainThread(
^{
[weakSelf
onCallSetSearchActive:[params[@"active"] boolValue]
withConnection:connection];
},
responder);
}]; }];
[connection receive:@"isSearchActive" withBlock:^(NSDictionary *params, id<FlipperResponder> responder) { [connection receive:@"isSearchActive"
FlipperPerformBlockOnMainThread(^{ [weakSelf onCallIsSearchActiveWithConnection: responder]; }, responder); withBlock:^(NSDictionary* params, id<FlipperResponder> responder) {
FlipperPerformBlockOnMainThread(
^{
[weakSelf onCallIsSearchActiveWithConnection:responder];
},
responder);
}]; }];
[connection receive:@"isConsoleEnabled" withBlock:^(NSDictionary *params, id<FlipperResponder> responder) { [connection receive:@"isConsoleEnabled"
FlipperPerformBlockOnMainThread(^{ [responder success: @{@"isEnabled": @NO}];}, responder); withBlock:^(NSDictionary* params, id<FlipperResponder> responder) {
FlipperPerformBlockOnMainThread(
^{
[responder success:@{@"isEnabled" : @NO}];
},
responder);
}]; }];
[connection receive:@"getSearchResults" withBlock:^(NSDictionary *params, id<FlipperResponder> responder) { [connection receive:@"getSearchResults"
FlipperPerformBlockOnMainThread(^{ [weakSelf onCallGetSearchResults: params[@"query"] withResponder: responder]; }, responder); withBlock:^(NSDictionary* params, id<FlipperResponder> responder) {
FlipperPerformBlockOnMainThread(
^{
[weakSelf onCallGetSearchResults:params[@"query"]
withResponder:responder];
},
responder);
}]; }];
} }
@@ -143,7 +189,10 @@
[responder success:rootNode]; [responder success:rootNode];
} }
- (void)populateAllNodesFromNode:(nonnull NSString *)identifier inDictionary:(nonnull NSMutableDictionary<NSString*, NSDictionary*> *)mutableDict { - (void)populateAllNodesFromNode:(nonnull NSString*)identifier
inDictionary:
(nonnull NSMutableDictionary<NSString*, NSDictionary*>*)
mutableDict {
NSDictionary* nodeDict = [self getNode:identifier]; NSDictionary* nodeDict = [self getNode:identifier];
mutableDict[identifier] = nodeDict; mutableDict[identifier] = nodeDict;
NSArray* arr = nodeDict[@"children"]; NSArray* arr = nodeDict[@"children"];
@@ -153,7 +202,9 @@
return; return;
} }
- (void)populateAllNodesFromNode:(nonnull NSString *)identifier inArray:(nonnull NSMutableArray<NSDictionary *> *)mutableArray { - (void)populateAllNodesFromNode:(nonnull NSString*)identifier
inArray:(nonnull NSMutableArray<NSDictionary*>*)
mutableArray {
NSDictionary* nodeDict = [self getNode:identifier]; NSDictionary* nodeDict = [self getNode:identifier];
if (nodeDict == nil) { if (nodeDict == nil) {
return; return;
@@ -170,15 +221,23 @@
NSString* identifier = [self trackObject:_rootNode]; NSString* identifier = [self trackObject:_rootNode];
NSDictionary* rootNode = [self getNode:identifier]; NSDictionary* rootNode = [self getNode:identifier];
if (!rootNode) { if (!rootNode) {
return [responder error:@{@"error": [NSString stringWithFormat:@"getNode returned nil for the rootNode %@, while getting all the nodes", identifier]}]; return [responder error:@{
@"error" : [NSString
stringWithFormat:
@"getNode returned nil for the rootNode %@, while getting all the nodes",
identifier]
}];
} }
[allNodes addObject:rootNode]; [allNodes addObject:rootNode];
NSMutableDictionary* allNodesDict = @{}.mutableCopy; NSMutableDictionary* allNodesDict = @{}.mutableCopy;
[self populateAllNodesFromNode:identifier inDictionary:allNodesDict]; [self populateAllNodesFromNode:identifier inDictionary:allNodesDict];
[responder success:@{@"allNodes": @{@"rootElement": identifier, @"elements": allNodesDict}}]; [responder success:@{
@"allNodes" : @{@"rootElement" : identifier, @"elements" : allNodesDict}
}];
} }
- (NSMutableArray*)getChildrenForNode:(id)node withDescriptor:(SKNodeDescriptor*)descriptor { - (NSMutableArray*)getChildrenForNode:(id)node
withDescriptor:(SKNodeDescriptor*)descriptor {
NSMutableArray* children = [NSMutableArray new]; NSMutableArray* children = [NSMutableArray new];
for (NSUInteger i = 0; i < [descriptor childCountForNode:node]; i++) { for (NSUInteger i = 0; i < [descriptor childCountForNode:node]; i++) {
id childNode = [descriptor childForNode:node atIndex:i]; id childNode = [descriptor childForNode:node atIndex:i];
@@ -191,7 +250,8 @@
return children; return children;
} }
- (void)onCallGetNodes:(NSArray<NSDictionary *> *)nodeIds withResponder:(id<FlipperResponder>)responder { - (void)onCallGetNodes:(NSArray<NSDictionary*>*)nodeIds
withResponder:(id<FlipperResponder>)responder {
NSMutableArray<NSDictionary*>* elements = [NSMutableArray new]; NSMutableArray<NSDictionary*>* elements = [NSMutableArray new];
for (id nodeId in nodeIds) { for (id nodeId in nodeIds) {
@@ -214,8 +274,7 @@
SKLog(@"node is nil, trying to setData: \ SKLog(@"node is nil, trying to setData: \
objectId: %@ \ objectId: %@ \
path: %@ \ path: %@ \
value: %@", value: %@", objectId, path, value);
objectId, path, value);
return; return;
} }
@@ -225,25 +284,37 @@
return; return;
} }
SKNodeDescriptor *descriptor = [_descriptorMapper descriptorForClass: [node class]]; SKNodeDescriptor* descriptor =
[_descriptorMapper descriptorForClass:[node class]];
NSString* dotJoinedPath = [path componentsJoinedByString:@"."]; NSString* dotJoinedPath = [path componentsJoinedByString:@"."];
SKNodeUpdateData updateDataForPath = [[descriptor dataMutationsForNode: node] objectForKey: dotJoinedPath]; SKNodeUpdateData updateDataForPath =
[[descriptor dataMutationsForNode:node] objectForKey:dotJoinedPath];
if (updateDataForPath != nil) { if (updateDataForPath != nil) {
const auto identifierForInvalidation = [descriptor identifierForInvalidation:node]; const auto identifierForInvalidation =
id nodeForInvalidation = [_trackedObjects objectForKey:identifierForInvalidation]; [descriptor identifierForInvalidation:node];
SKNodeDescriptor *descriptorForInvalidation = [_descriptorMapper descriptorForClass:[nodeForInvalidation class]]; id nodeForInvalidation =
[_trackedObjects objectForKey:identifierForInvalidation];
SKNodeDescriptor* descriptorForInvalidation =
[_descriptorMapper descriptorForClass:[nodeForInvalidation class]];
updateDataForPath(value); updateDataForPath(value);
NSMutableArray* nodesForInvalidation = [NSMutableArray new]; NSMutableArray* nodesForInvalidation = [NSMutableArray new];
[self populateAllNodesFromNode:[descriptorForInvalidation identifierForNode:nodeForInvalidation] inArray:nodesForInvalidation]; [self populateAllNodesFromNode:[descriptorForInvalidation
[connection send: @"invalidateWithData" withParams: @{@"nodes": nodesForInvalidation}]; identifierForNode:nodeForInvalidation]
inArray:nodesForInvalidation];
[connection send:@"invalidateWithData"
withParams:@{@"nodes" : nodesForInvalidation}];
} }
} }
- (void)onCallGetSearchResults:(NSString *)query withResponder:(id<FlipperResponder>)responder { - (void)onCallGetSearchResults:(NSString*)query
withResponder:(id<FlipperResponder>)responder {
const auto alreadyAddedElements = [NSMutableSet<NSString*> new]; const auto alreadyAddedElements = [NSMutableSet<NSString*> new];
SKSearchResultNode *matchTree = [self searchForQuery:(NSString *)[query lowercaseString] fromNode:(id)_rootNode withElementsAlreadyAdded: alreadyAddedElements]; SKSearchResultNode* matchTree =
[self searchForQuery:(NSString*)[query lowercaseString]
fromNode:(id)_rootNode
withElementsAlreadyAdded:alreadyAddedElements];
[responder success:@{ [responder success:@{
@"results" : [matchTree toNSDictionary] ?: [NSNull null], @"results" : [matchTree toNSDictionary] ?: [NSNull null],
@@ -252,15 +323,18 @@
return; return;
} }
- (void)onCallSetHighlighted:(NSString *)objectId withResponder:(id<FlipperResponder>)responder { - (void)onCallSetHighlighted:(NSString*)objectId
withResponder:(id<FlipperResponder>)responder {
if (_lastHighlightedNode != nil) { if (_lastHighlightedNode != nil) {
id lastHighlightedObject = [_trackedObjects objectForKey: _lastHighlightedNode]; id lastHighlightedObject =
[_trackedObjects objectForKey:_lastHighlightedNode];
if (lastHighlightedObject == nil) { if (lastHighlightedObject == nil) {
[responder error:@{@"error" : @"unable to get last highlighted object"}]; [responder error:@{@"error" : @"unable to get last highlighted object"}];
return; return;
} }
SKNodeDescriptor *descriptor = [self->_descriptorMapper descriptorForClass: [lastHighlightedObject class]]; SKNodeDescriptor* descriptor = [self->_descriptorMapper
descriptorForClass:[lastHighlightedObject class]];
[descriptor setHighlighted:NO forNode:lastHighlightedObject]; [descriptor setHighlighted:NO forNode:lastHighlightedObject];
_lastHighlightedNode = nil; _lastHighlightedNode = nil;
@@ -276,28 +350,30 @@
return; return;
} }
SKNodeDescriptor *descriptor = [self->_descriptorMapper descriptorForClass: [object class]]; SKNodeDescriptor* descriptor =
[self->_descriptorMapper descriptorForClass:[object class]];
[descriptor setHighlighted:YES forNode:object]; [descriptor setHighlighted:YES forNode:object];
_lastHighlightedNode = objectId; _lastHighlightedNode = objectId;
} }
- (void)onCallSetSearchActive:(BOOL)active withConnection:(id<FlipperConnection>)connection { - (void)onCallSetSearchActive:(BOOL)active
withConnection:(id<FlipperConnection>)connection {
if (active) { if (active) {
[_tapListener mountWithFrame:[[UIScreen mainScreen] bounds]]; [_tapListener mountWithFrame:[[UIScreen mainScreen] bounds]];
__block id<NSObject> rootNode = _rootNode; __block id<NSObject> rootNode = _rootNode;
[_tapListener listenForTapWithBlock:^(CGPoint touchPoint) { [_tapListener listenForTapWithBlock:^(CGPoint touchPoint) {
SKTouch *touch = SKTouch* touch = [[SKTouch alloc]
[[SKTouch alloc] initWithTouchPoint: touchPoint initWithTouchPoint:touchPoint
withRootNode:rootNode withRootNode:rootNode
withDescriptorMapper:self->_descriptorMapper withDescriptorMapper:self->_descriptorMapper
finishWithBlock:^(NSArray<NSString*>* path) { finishWithBlock:^(NSArray<NSString*>* path) {
[connection send: @"select" [connection send:@"select" withParams:@{@"path" : path}];
withParams: @{ @"path": path }];
}]; }];
SKNodeDescriptor *descriptor = [self->_descriptorMapper descriptorForClass: [rootNode class]]; SKNodeDescriptor* descriptor =
[self->_descriptorMapper descriptorForClass:[rootNode class]];
[descriptor hitTest:touch forNode:rootNode]; [descriptor hitTest:touch forNode:rootNode];
}]; }];
} else { } else {
@@ -310,7 +386,8 @@
} }
- (void)invalidateNode:(id<NSObject>)node { - (void)invalidateNode:(id<NSObject>)node {
SKNodeDescriptor *descriptor = [_descriptorMapper descriptorForClass: [node class]]; SKNodeDescriptor* descriptor =
[_descriptorMapper descriptorForClass:[node class]];
if (descriptor == nil) { if (descriptor == nil) {
return; return;
} }
@@ -330,7 +407,10 @@
_invalidateMessageQueued = true; _invalidateMessageQueued = true;
if (_lastInvalidateMessage.timeIntervalSinceNow < -1) { if (_lastInvalidateMessage.timeIntervalSinceNow < -1) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 500 * NSEC_PER_MSEC), dispatch_get_main_queue(), ^{ dispatch_after(
dispatch_time(DISPATCH_TIME_NOW, 500 * NSEC_PER_MSEC),
dispatch_get_main_queue(),
^{
[self reportInvalidatedObjects]; [self reportInvalidatedObjects];
}); });
} }
@@ -342,7 +422,9 @@
for (NSString* nodeId in self->_invalidObjects) { for (NSString* nodeId in self->_invalidObjects) {
[nodes addObject:[NSDictionary dictionaryWithObject:nodeId forKey:@"id"]]; [nodes addObject:[NSDictionary dictionaryWithObject:nodeId forKey:@"id"]];
} }
[self->_connection send: @"invalidate" withParams: [NSDictionary dictionaryWithObject: nodes forKey: @"nodes"]]; [self->_connection send:@"invalidate"
withParams:[NSDictionary dictionaryWithObject:nodes
forKey:@"nodes"]];
self->_lastInvalidateMessage = [NSDate date]; self->_lastInvalidateMessage = [NSDate date];
self->_invalidObjects = [NSMutableSet new]; self->_invalidObjects = [NSMutableSet new];
self->_invalidateMessageQueued = false; self->_invalidateMessageQueued = false;
@@ -350,7 +432,8 @@
} }
- (void)updateNodeReference:(id<NSObject>)node { - (void)updateNodeReference:(id<NSObject>)node {
SKNodeDescriptor *descriptor = [_descriptorMapper descriptorForClass: [node class]]; SKNodeDescriptor* descriptor =
[_descriptorMapper descriptorForClass:[node class]];
if (descriptor == nil) { if (descriptor == nil) {
return; return;
} }
@@ -359,8 +442,11 @@
[_trackedObjects setObject:node forKey:nodeId]; [_trackedObjects setObject:node forKey:nodeId];
} }
- (SKSearchResultNode *)searchForQuery:(NSString *)query fromNode:(id)node withElementsAlreadyAdded:(NSMutableSet<NSString *> *)alreadyAdded { - (SKSearchResultNode*)searchForQuery:(NSString*)query
SKNodeDescriptor *descriptor = [_descriptorMapper descriptorForClass: [node class]]; fromNode:(id)node
withElementsAlreadyAdded:(NSMutableSet<NSString*>*)alreadyAdded {
SKNodeDescriptor* descriptor =
[_descriptorMapper descriptorForClass:[node class]];
if (node == nil || descriptor == nil) { if (node == nil || descriptor == nil) {
return nil; return nil;
} }
@@ -373,7 +459,9 @@
for (auto i = 0; i < [descriptor childCountForNode:node]; i++) { for (auto i = 0; i < [descriptor childCountForNode:node]; i++) {
id child = [descriptor childForNode:node atIndex:i]; id child = [descriptor childForNode:node atIndex:i];
if (child) { if (child) {
SKSearchResultNode *childTree = [self searchForQuery: query fromNode: child withElementsAlreadyAdded:alreadyAdded]; SKSearchResultNode* childTree = [self searchForQuery:query
fromNode:child
withElementsAlreadyAdded:alreadyAdded];
if (childTree != nil) { if (childTree != nil) {
if (childTrees == nil) { if (childTrees == nil) {
childTrees = [NSMutableArray new]; childTrees = [NSMutableArray new];
@@ -384,12 +472,12 @@
} }
if (isMatch || childTrees != nil) { if (isMatch || childTrees != nil) {
NSDictionary* element = [self getNode:nodeId]; NSDictionary* element = [self getNode:nodeId];
if (nodeId == nil || element == nil) { if (nodeId == nil || element == nil) {
return nil; return nil;
} }
NSMutableArray<NSString *> *descriptorChildElements = [element objectForKey: @"children"]; NSMutableArray<NSString*>* descriptorChildElements =
[element objectForKey:@"children"];
NSMutableDictionary* newElement = [element mutableCopy]; NSMutableDictionary* newElement = [element mutableCopy];
NSMutableArray<NSString*>* childElementsToReturn = [NSMutableArray new]; NSMutableArray<NSString*>* childElementsToReturn = [NSMutableArray new];
@@ -415,7 +503,8 @@
return nil; return nil;
} }
SKNodeDescriptor *nodeDescriptor = [_descriptorMapper descriptorForClass: [node class]]; SKNodeDescriptor* nodeDescriptor =
[_descriptorMapper descriptorForClass:[node class]];
if (nodeDescriptor == nil) { if (nodeDescriptor == nil) {
SKLog(@"No registered descriptor for class: %@", [node class]); SKLog(@"No registered descriptor for class: %@", [node class]);
return nil; return nil;
@@ -441,11 +530,12 @@
data[namedPair.name] = namedPair.value; data[namedPair.name] = namedPair.value;
} }
NSMutableArray *children = [self getChildrenForNode: node withDescriptor:nodeDescriptor]; NSMutableArray* children = [self getChildrenForNode:node
withDescriptor:nodeDescriptor];
NSDictionary *nodeDic = NSDictionary* nodeDic = @{
@{ // We shouldn't get nil for id/name/decoration, but let's not crash if we
// We shouldn't get nil for id/name/decoration, but let's not crash if we do. // do.
@"id" : [nodeDescriptor identifierForNode:node] ?: @"(unknown)", @"id" : [nodeDescriptor identifierForNode:node] ?: @"(unknown)",
@"name" : [nodeDescriptor nameForNode:node] ?: @"(unknown)", @"name" : [nodeDescriptor nameForNode:node] ?: @"(unknown)",
@"children" : children, @"children" : children,
@@ -458,7 +548,8 @@
} }
- (NSString*)trackObject:(id)object { - (NSString*)trackObject:(id)object {
const SKNodeDescriptor *descriptor = [_descriptorMapper descriptorForClass: [object class]]; const SKNodeDescriptor* descriptor =
[_descriptorMapper descriptorForClass:[object class]];
NSString* objectIdentifier = [descriptor identifierForNode:object]; NSString* objectIdentifier = [descriptor identifierForNode:object];
if (objectIdentifier == nil) { if (objectIdentifier == nil) {

View File

@@ -15,8 +15,7 @@
#import "SKViewControllerDescriptor.h" #import "SKViewControllerDescriptor.h"
#import "SKViewDescriptor.h" #import "SKViewDescriptor.h"
@implementation SKDescriptorMapper @implementation SKDescriptorMapper {
{
NSMutableDictionary<NSString*, SKNodeDescriptor*>* _descriptors; NSMutableDictionary<NSString*, SKNodeDescriptor*>* _descriptors;
} }
@@ -24,15 +23,20 @@
if (self = [super init]) { if (self = [super init]) {
_descriptors = [NSMutableDictionary new]; _descriptors = [NSMutableDictionary new];
[self registerDescriptor: [[SKApplicationDescriptor alloc] initWithDescriptorMapper: self] [self registerDescriptor:[[SKApplicationDescriptor alloc]
initWithDescriptorMapper:self]
forClass:[UIApplication class]]; forClass:[UIApplication class]];
[self registerDescriptor: [[SKViewControllerDescriptor alloc] initWithDescriptorMapper: self] [self registerDescriptor:[[SKViewControllerDescriptor alloc]
initWithDescriptorMapper:self]
forClass:[UIViewController class]]; forClass:[UIViewController class]];
[self registerDescriptor: [[SKScrollViewDescriptor alloc] initWithDescriptorMapper: self] [self registerDescriptor:[[SKScrollViewDescriptor alloc]
initWithDescriptorMapper:self]
forClass:[UIScrollView class]]; forClass:[UIScrollView class]];
[self registerDescriptor: [[SKButtonDescriptor alloc] initWithDescriptorMapper: self] [self registerDescriptor:[[SKButtonDescriptor alloc]
initWithDescriptorMapper:self]
forClass:[UIButton class]]; forClass:[UIButton class]];
[self registerDescriptor: [[SKViewDescriptor alloc] initWithDescriptorMapper: self] [self registerDescriptor:[[SKViewDescriptor alloc]
initWithDescriptorMapper:self]
forClass:[UIView class]]; forClass:[UIView class]];
} }

View File

@@ -10,8 +10,8 @@
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import "SKInvalidation.h" #import "SKInvalidation.h"
#import "UIView+SKInvalidation.h"
#import "UICollectionView+SKInvalidation.h" #import "UICollectionView+SKInvalidation.h"
#import "UIView+SKInvalidation.h"
@implementation SKInvalidation @implementation SKInvalidation
@@ -32,12 +32,14 @@
[UIView enableInvalidation]; [UIView enableInvalidation];
[UICollectionView enableInvalidations]; [UICollectionView enableInvalidations];
[[NSNotificationCenter defaultCenter] addObserver:self [[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(windowDidBecomeVisible:) selector:@selector(windowDidBecomeVisible:)
name:UIWindowDidBecomeVisibleNotification name:UIWindowDidBecomeVisibleNotification
object:nil]; object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self [[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(windowDidBecomeHidden:) selector:@selector(windowDidBecomeHidden:)
name:UIWindowDidBecomeHiddenNotification name:UIWindowDidBecomeHiddenNotification
object:nil]; object:nil];
@@ -45,11 +47,13 @@
} }
+ (void)windowDidBecomeVisible:(NSNotification*)notification { + (void)windowDidBecomeVisible:(NSNotification*)notification {
[[SKInvalidation sharedInstance].delegate invalidateNode:[notification.object nextResponder]]; [[SKInvalidation sharedInstance].delegate
invalidateNode:[notification.object nextResponder]];
} }
+ (void)windowDidBecomeHidden:(NSNotification*)notification { + (void)windowDidBecomeHidden:(NSNotification*)notification {
[[SKInvalidation sharedInstance].delegate invalidateNode:[notification.object nextResponder]]; [[SKInvalidation sharedInstance].delegate
invalidateNode:[notification.object nextResponder]];
} }
@end @end

View File

@@ -15,8 +15,8 @@ typedef void (^SKNodeUpdateData)(id value);
/** /**
A SKNodeDescriptor is an object which know how to expose an Object of type T A SKNodeDescriptor is an object which know how to expose an Object of type T
to SonarKitLayoutPlugin. This class is the extension point for SonarKitLayoutPlugin and to SonarKitLayoutPlugin. This class is the extension point for
is how custom objects or data can be exposed to Sonar. SonarKitLayoutPlugin and is how custom objects or data can be exposed to Sonar.
*/ */
@interface SKNodeDescriptor<__covariant T> : NSObject @interface SKNodeDescriptor<__covariant T> : NSObject
@@ -27,8 +27,8 @@ typedef void (^SKNodeUpdateData)(id value);
- (void)setUp; - (void)setUp;
/** /**
Initializes the node-descriptor with a SKDescriptorMapper which contains mappings Initializes the node-descriptor with a SKDescriptorMapper which contains
between Class -> SKNodeDescriptor<Class>. mappings between Class -> SKNodeDescriptor<Class>.
*/ */
- (instancetype)initWithDescriptorMapper:(SKDescriptorMapper*)mapper; - (instancetype)initWithDescriptorMapper:(SKDescriptorMapper*)mapper;
@@ -39,20 +39,21 @@ typedef void (^SKNodeUpdateData)(id value);
/** /**
A globally unique ID used to identify a node in the hierarchy. This is used A globally unique ID used to identify a node in the hierarchy. This is used
in the communication between SonarKitLayoutPlugin and the Sonar desktop application in the communication between SonarKitLayoutPlugin and the Sonar desktop
in order to identify nodes. application in order to identify nodes.
*/ */
- (NSString*)identifierForNode:(T)node; - (NSString*)identifierForNode:(T)node;
/** /**
An ID which is equal between reflowing components is needed to get the identifier of root An ID which is equal between reflowing components is needed to get the
node of a tree which need to be invalidated on FlipperKitLayoutPlugin side. identifier of root node of a tree which need to be invalidated on
FlipperKitLayoutPlugin side.
*/ */
- (NSString*)identifierForInvalidation:(T)node; - (NSString*)identifierForInvalidation:(T)node;
/** /**
The name used to identify this node in the Sonar desktop application. This is what The name used to identify this node in the Sonar desktop application. This is
will be visible in the hierarchy. what will be visible in the hierarchy.
*/ */
- (NSString*)nameForNode:(T)node; - (NSString*)nameForNode:(T)node;
@@ -67,29 +68,30 @@ typedef void (^SKNodeUpdateData)(id value);
- (id)childForNode:(T)node atIndex:(NSUInteger)index; - (id)childForNode:(T)node atIndex:(NSUInteger)index;
/** /**
Get the data to show for this node in the sidebar of the Sonar application. The objects Get the data to show for this node in the sidebar of the Sonar application. The
will be shown in order by SKNamed.name as their header. objects will be shown in order by SKNamed.name as their header.
*/ */
- (NSArray<SKNamed<NSDictionary*>*>*)dataForNode:(T)node; - (NSArray<SKNamed<NSDictionary*>*>*)dataForNode:(T)node;
/** /**
Get the attributes for this node. Attributes will be showed in the Sonar application right Get the attributes for this node. Attributes will be showed in the Sonar
next to the name of the node. application right next to the name of the node.
*/ */
- (NSArray<SKNamed<NSString*>*>*)attributesForNode:(T)node; - (NSArray<SKNamed<NSString*>*>*)attributesForNode:(T)node;
/** /**
A mapping of the path for a specific value, and a block responsible for updating A mapping of the path for a specific value, and a block responsible for
its corresponding value for a specific node. updating its corresponding value for a specific node.
The paths (string) is dependent on what `dataForNode` returns (e.g "SKNodeDescriptor.name"). The paths (string) is dependent on what `dataForNode` returns (e.g
"SKNodeDescriptor.name").
*/ */
- (NSDictionary<NSString*, SKNodeUpdateData>*)dataMutationsForNode:(T)node; - (NSDictionary<NSString*, SKNodeUpdateData>*)dataMutationsForNode:(T)node;
/** /**
This is used in order to highlight any specific node which is currently This is used in order to highlight any specific node which is currently
selected in the Sonar application. The plugin automatically takes care of de-selecting selected in the Sonar application. The plugin automatically takes care of
the previously highlighted node. de-selecting the previously highlighted node.
*/ */
- (void)setHighlighted:(BOOL)highlighted forNode:(T)node; - (void)setHighlighted:(BOOL)highlighted forNode:(T)node;

View File

@@ -10,8 +10,7 @@
#import "SKNodeDescriptor.h" #import "SKNodeDescriptor.h"
#import <FlipperKitLayoutTextSearchable/FKTextSearchable.h> #import <FlipperKitLayoutTextSearchable/FKTextSearchable.h>
@implementation SKNodeDescriptor @implementation SKNodeDescriptor {
{
SKDescriptorMapper* _mapper; SKDescriptorMapper* _mapper;
} }
@@ -30,11 +29,11 @@
} }
- (NSString*)identifierForNode:(id)node { - (NSString*)identifierForNode:(id)node {
@throw [NSString stringWithFormat:@"need to implement %@", NSStringFromSelector(_cmd)]; @throw [NSString
stringWithFormat:@"need to implement %@", NSStringFromSelector(_cmd)];
} }
- (NSString *)identifierForInvalidation:(id)node - (NSString*)identifierForInvalidation:(id)node {
{
return [self identifierForNode:node]; return [self identifierForNode:node];
} }
@@ -43,11 +42,13 @@
} }
- (NSUInteger)childCountForNode:(id)node { - (NSUInteger)childCountForNode:(id)node {
@throw [NSString stringWithFormat:@"need to implement %@", NSStringFromSelector(_cmd)]; @throw [NSString
stringWithFormat:@"need to implement %@", NSStringFromSelector(_cmd)];
} }
- (id)childForNode:(id)node atIndex:(NSUInteger)index { - (id)childForNode:(id)node atIndex:(NSUInteger)index {
@throw [NSString stringWithFormat:@"need to implement %@", NSStringFromSelector(_cmd)]; @throw [NSString
stringWithFormat:@"need to implement %@", NSStringFromSelector(_cmd)];
} }
- (NSDictionary<NSString*, SKNodeUpdateData>*)dataMutationsForNode:(id)node { - (NSDictionary<NSString*, SKNodeUpdateData>*)dataMutationsForNode:(id)node {
@@ -87,10 +88,11 @@
} }
- (BOOL)string:(NSString*)string contains:(NSString*)substring { - (BOOL)string:(NSString*)string contains:(NSString*)substring {
return string != nil && substring != nil && [string rangeOfString: substring options: NSCaseInsensitiveSearch].location != NSNotFound; return string != nil && substring != nil &&
[string rangeOfString:substring options:NSCaseInsensitiveSearch]
.location != NSNotFound;
} }
@end @end
#endif #endif

View File

@@ -28,6 +28,7 @@ public:
operator id<NSObject>() const noexcept { operator id<NSObject>() const noexcept {
return _actual ?: [NSNull null]; return _actual ?: [NSNull null];
} }
protected: protected:
id<NSObject> _actual; id<NSObject> _actual;
}; };
@@ -46,6 +47,7 @@ public:
convertToMutable(); convertToMutable();
return _actual; return _actual;
} }
protected: protected:
BOOL _convertedToMutable = NO; BOOL _convertedToMutable = NO;
void convertToMutable(); void convertToMutable();

View File

@@ -10,24 +10,15 @@
#import "SKObject.h" #import "SKObject.h"
SKObject::SKObject(CGRect rect) { SKObject::SKObject(CGRect rect) {
_actual = @{ _actual = @{@"origin" : SKObject(rect.origin), @"size" : SKObject(rect.size)};
@"origin": SKObject(rect.origin),
@"size": SKObject(rect.size)
};
} }
SKObject::SKObject(CGSize size) { SKObject::SKObject(CGSize size) {
_actual = @{ _actual = @{@"height" : @(size.height), @"width" : @(size.width)};
@"height": @(size.height),
@"width": @(size.width)
};
} }
SKObject::SKObject(CGPoint point) { SKObject::SKObject(CGPoint point) {
_actual = @{ _actual = @{@"x" : @(point.x), @"y" : @(point.y)};
@"x": @(point.x),
@"y": @(point.y)
};
} }
SKObject::SKObject(UIEdgeInsets insets) { SKObject::SKObject(UIEdgeInsets insets) {
@@ -70,7 +61,9 @@ static id<NSObject> _objectValue(id<NSObject> object) {
return object; return object;
} }
static NSDictionary<NSString *, id<NSObject>> *_SKValue(id<NSObject> object, BOOL isMutable) { static NSDictionary<NSString*, id<NSObject>>* _SKValue(
id<NSObject> object,
BOOL isMutable) {
NSString* type = _objectType(object); NSString* type = _objectType(object);
id<NSObject> value = _objectValue(object); id<NSObject> value = _objectValue(object);
@@ -81,7 +74,8 @@ static NSDictionary<NSString *, id<NSObject>> *_SKValue(id<NSObject> object, BOO
}; };
} }
static NSDictionary *_SKMutable(const NSDictionary<NSString *, id<NSObject>> *skObject) { static NSDictionary* _SKMutable(
const NSDictionary<NSString*, id<NSObject>>* skObject) {
NSMutableDictionary* mutableObject = [NSMutableDictionary new]; NSMutableDictionary* mutableObject = [NSMutableDictionary new];
for (NSString* key : skObject) { for (NSString* key : skObject) {
id<NSObject> value = skObject[key]; id<NSObject> value = skObject[key];
@@ -104,7 +98,8 @@ void SKMutableObject::convertToMutable() {
return; return;
} }
if (_objectType(_actual) == nil && [_actual isKindOfClass: [NSDictionary class]]) { if (_objectType(_actual) == nil &&
[_actual isKindOfClass:[NSDictionary class]]) {
auto object = (const NSDictionary<NSString*, id<NSObject>>*)_actual; auto object = (const NSDictionary<NSString*, id<NSObject>>*)_actual;
_actual = _SKMutable(object); _actual = _SKMutable(object);
} else { } else {

View File

@@ -7,6 +7,7 @@
#import "SKTapListener.h" #import "SKTapListener.h"
@interface SKTapListenerImpl : NSObject<SKTapListener, UIGestureRecognizerDelegate> @interface SKTapListenerImpl
: NSObject<SKTapListener, UIGestureRecognizerDelegate>
@end @end

View File

@@ -13,8 +13,7 @@
#import <FlipperKitHighlightOverlay/SKHighlightOverlay.h> #import <FlipperKitHighlightOverlay/SKHighlightOverlay.h>
@implementation SKTapListenerImpl @implementation SKTapListenerImpl {
{
NSMutableArray<SKTapReceiver>* _receiversWaitingForInput; NSMutableArray<SKTapReceiver>* _receiversWaitingForInput;
UITapGestureRecognizer* _gestureRecognizer; UITapGestureRecognizer* _gestureRecognizer;
@@ -27,7 +26,8 @@
if (self = [super init]) { if (self = [super init]) {
_receiversWaitingForInput = [NSMutableArray new]; _receiversWaitingForInput = [NSMutableArray new];
_gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget: self action: nil]; _gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
action:nil];
_gestureRecognizer.delegate = self; _gestureRecognizer.delegate = self;
_isMounted = NO; _isMounted = NO;
@@ -71,7 +71,8 @@
[_receiversWaitingForInput addObject:receiver]; [_receiversWaitingForInput addObject:receiver];
} }
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { - (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
shouldReceiveTouch:(UITouch*)touch {
if ([_receiversWaitingForInput count] == 0) { if ([_receiversWaitingForInput count] == 0) {
return YES; return YES;
} }

View File

@@ -10,8 +10,7 @@
#import "SKTouch.h" #import "SKTouch.h"
#import "SKNodeDescriptor.h" #import "SKNodeDescriptor.h"
@implementation SKTouch @implementation SKTouch {
{
SKTouchFinishDelegate _onFinish; SKTouchFinishDelegate _onFinish;
NSMutableArray<NSString*>* _path; NSMutableArray<NSString*>* _path;
@@ -36,11 +35,13 @@
return self; return self;
} }
- (void)continueWithChildIndex:(NSUInteger)childIndex withOffset:(CGPoint)offset { - (void)continueWithChildIndex:(NSUInteger)childIndex
withOffset:(CGPoint)offset {
_currentTouchPoint.x -= offset.x; _currentTouchPoint.x -= offset.x;
_currentTouchPoint.y -= offset.y; _currentTouchPoint.y -= offset.y;
SKNodeDescriptor *descriptor = [_descriptorMapper descriptorForClass: [_currentNode class]]; SKNodeDescriptor* descriptor =
[_descriptorMapper descriptorForClass:[_currentNode class]];
_currentNode = [descriptor childForNode:_currentNode atIndex:childIndex]; _currentNode = [descriptor childForNode:_currentNode atIndex:childIndex];
descriptor = [_descriptorMapper descriptorForClass:[_currentNode class]]; descriptor = [_descriptorMapper descriptorForClass:[_currentNode class]];

View File

@@ -18,11 +18,15 @@ FB_LINKABLE(UICollectionView_SKInvalidation)
+ (void)enableInvalidations { + (void)enableInvalidations {
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{
swizzleMethods([self class], @selector(cellForItemAtIndexPath:), @selector(swizzle_cellForItemAtIndexPath:)); swizzleMethods(
[self class],
@selector(cellForItemAtIndexPath:),
@selector(swizzle_cellForItemAtIndexPath:));
}); });
} }
- (UICollectionViewCell *)swizzle_cellForItemAtIndexPath:(NSIndexPath *)indexPath { - (UICollectionViewCell*)swizzle_cellForItemAtIndexPath:
(NSIndexPath*)indexPath {
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[[SKInvalidation sharedInstance].delegate invalidateNode:self]; [[SKInvalidation sharedInstance].delegate invalidateNode:self];
}); });

View File

@@ -56,11 +56,8 @@ FB_LINKABLE(UIColor_SonarValueCoder)
} }
NSUInteger intColor = (alpha << 24) | (red << 16) | (green << 8) | blue; NSUInteger intColor = (alpha << 24) | (red << 16) | (green << 8) | blue;
return @{ return
@"__type__": @"color", @{@"__type__" : @"color", @"__mutable__" : @NO, @"value" : @(intColor)};
@"__mutable__": @NO,
@"value": @(intColor)
};
} }
@end @end

View File

@@ -20,16 +20,22 @@ FB_LINKABLE(UIView_SKInvalidation)
+ (void)enableInvalidation { + (void)enableInvalidation {
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{
swizzleMethods([self class], @selector(setHidden:), @selector(swizzle_setHidden:)); swizzleMethods(
swizzleMethods([self class], @selector(addSubview:), @selector(swizzle_addSubview:)); [self class], @selector(setHidden:), @selector(swizzle_setHidden:));
swizzleMethods([self class], @selector(removeFromSuperview), @selector(swizzle_removeFromSuperview)); swizzleMethods(
[self class], @selector(addSubview:), @selector(swizzle_addSubview:));
swizzleMethods(
[self class],
@selector(removeFromSuperview),
@selector(swizzle_removeFromSuperview));
}); });
} }
- (void)swizzle_setHidden:(BOOL)hidden { - (void)swizzle_setHidden:(BOOL)hidden {
[self swizzle_setHidden:hidden]; [self swizzle_setHidden:hidden];
id<SKInvalidationDelegate> delegate = [SKInvalidation sharedInstance].delegate; id<SKInvalidationDelegate> delegate =
[SKInvalidation sharedInstance].delegate;
if (delegate != nil) { if (delegate != nil) {
[delegate invalidateNode:self.superview]; [delegate invalidateNode:self.superview];
} }
@@ -38,14 +44,16 @@ FB_LINKABLE(UIView_SKInvalidation)
- (void)swizzle_addSubview:(UIView*)view { - (void)swizzle_addSubview:(UIView*)view {
[self swizzle_addSubview:view]; [self swizzle_addSubview:view];
id<SKInvalidationDelegate> delegate = [SKInvalidation sharedInstance].delegate; id<SKInvalidationDelegate> delegate =
[SKInvalidation sharedInstance].delegate;
if (delegate != nil) { if (delegate != nil) {
[delegate invalidateNode:view]; [delegate invalidateNode:view];
} }
} }
- (void)swizzle_removeFromSuperview { - (void)swizzle_removeFromSuperview {
id<SKInvalidationDelegate> delegate = [SKInvalidation sharedInstance].delegate; id<SKInvalidationDelegate> delegate =
[SKInvalidation sharedInstance].delegate;
if (delegate != nil && self.superview != nil) { if (delegate != nil && self.superview != nil) {
[delegate invalidateNode:self.superview]; [delegate invalidateNode:self.superview];
} }

View File

@@ -9,9 +9,9 @@
#import "SKApplicationDescriptor.h" #import "SKApplicationDescriptor.h"
#import <objc/runtime.h>
#import "SKDescriptorMapper.h" #import "SKDescriptorMapper.h"
#import "SKHiddenWindow.h" #import "SKHiddenWindow.h"
#import <objc/runtime.h>
@implementation SKApplicationDescriptor @implementation SKApplicationDescriptor
@@ -28,12 +28,14 @@
} }
- (void)setHighlighted:(BOOL)highlighted forNode:(UIApplication*)node { - (void)setHighlighted:(BOOL)highlighted forNode:(UIApplication*)node {
SKNodeDescriptor *windowDescriptor = [self descriptorForClass: [UIWindow class]]; SKNodeDescriptor* windowDescriptor =
[self descriptorForClass:[UIWindow class]];
[windowDescriptor setHighlighted:highlighted forNode:[node keyWindow]]; [windowDescriptor setHighlighted:highlighted forNode:[node keyWindow]];
} }
- (void)hitTest:(SKTouch*)touch forNode:(UIApplication*)node { - (void)hitTest:(SKTouch*)touch forNode:(UIApplication*)node {
for (NSInteger index = [self childCountForNode: node] - 1; index >= 0; index--) { for (NSInteger index = [self childCountForNode:node] - 1; index >= 0;
index--) {
UIWindow* child = [self childForNode:node atIndex:index]; UIWindow* child = [self childForNode:node atIndex:index];
if (child.isHidden || child.alpha <= 0) { if (child.isHidden || child.alpha <= 0) {
continue; continue;
@@ -51,10 +53,11 @@
- (NSArray<UIWindow*>*)visibleChildrenForNode:(UIApplication*)node { - (NSArray<UIWindow*>*)visibleChildrenForNode:(UIApplication*)node {
NSMutableArray<UIWindow*>* children = [NSMutableArray new]; NSMutableArray<UIWindow*>* children = [NSMutableArray new];
for (UIWindow* window in node.windows) { for (UIWindow* window in node.windows) {
if ([window isKindOfClass: [SKHiddenWindow class]] if ([window isKindOfClass:[SKHiddenWindow class]] ||
|| [window isKindOfClass:objc_lookUpClass("FBAccessibilityOverlayWindow")] [window
|| [window isKindOfClass:objc_lookUpClass("UITextEffectsWindow")] isKindOfClass:objc_lookUpClass("FBAccessibilityOverlayWindow")] ||
|| [window isKindOfClass:objc_lookUpClass("FBStatusBarTrackingWindow")]) { [window isKindOfClass:objc_lookUpClass("UITextEffectsWindow")] ||
[window isKindOfClass:objc_lookUpClass("FBStatusBarTrackingWindow")]) {
continue; continue;
} }
[children addObject:window]; [children addObject:window];

View File

@@ -33,26 +33,30 @@
NSMutableArray* data = [NSMutableArray new]; NSMutableArray* data = [NSMutableArray new];
[data addObjectsFromArray:viewData]; [data addObjectsFromArray:viewData];
[data addObject: [data addObject:[SKNamed
[SKNamed newWithName: @"UIButton" newWithName:@"UIButton"
withValue:@{ withValue:@{
@"focused" : @(node.focused), @"focused" : @(node.focused),
@"enabled" : SKMutableObject(@(node.enabled)), @"enabled" : SKMutableObject(@(node.enabled)),
@"highlighted" : SKMutableObject(@(node.highlighted)), @"highlighted" : SKMutableObject(@(node.highlighted)),
@"titleEdgeInsets" : SKObject(node.titleEdgeInsets), @"titleEdgeInsets" : SKObject(node.titleEdgeInsets),
@"titleLabel": SKMutableObject(node.titleLabel.attributedText.string.stringByStandardizingPath), @"titleLabel" : SKMutableObject(
@"currentTitleColor": SKMutableObject(node.currentTitleColor), node.titleLabel.attributedText.string
}] .stringByStandardizingPath),
]; @"currentTitleColor" :
SKMutableObject(node.currentTitleColor),
}]];
return data; return data;
} }
- (NSDictionary<NSString *, SKNodeUpdateData> *)dataMutationsForNode:(UIButton *)node { - (NSDictionary<NSString*, SKNodeUpdateData>*)dataMutationsForNode:
NSDictionary *buttonMutations = @{ (UIButton*)node {
@"UIButton.titleLabel": ^(NSString *newValue) { NSDictionary* buttonMutations =
@{@"UIButton.titleLabel" : ^(NSString* newValue){
[node setTitle:newValue forState:node.state]; [node setTitle:newValue forState:node.state];
}, }
,
@"UIButton.currentTitleColor": ^(NSNumber *newValue) { @"UIButton.currentTitleColor": ^(NSNumber *newValue) {
[node setTitleColor: [UIColor fromSonarValue: newValue] forState: node.state]; [node setTitleColor: [UIColor fromSonarValue: newValue] forState: node.state];
}, },
@@ -62,7 +66,8 @@
@"UIButton.enabled": ^(NSNumber *enabled) { @"UIButton.enabled": ^(NSNumber *enabled) {
[node setEnabled: [enabled boolValue]]; [node setEnabled: [enabled boolValue]];
} }
}; }
;
SKNodeDescriptor* viewDescriptor = [self descriptorForClass:[UIView class]]; SKNodeDescriptor* viewDescriptor = [self descriptorForClass:[UIView class]];
NSDictionary* viewMutations = [viewDescriptor dataMutationsForNode:node]; NSDictionary* viewMutations = [viewDescriptor dataMutationsForNode:node];

View File

@@ -49,7 +49,8 @@
} }
- (void)hitTest:(SKTouch*)touch forNode:(UIScrollView*)node { - (void)hitTest:(SKTouch*)touch forNode:(UIScrollView*)node {
for (NSInteger index = [self childCountForNode: node] - 1; index >= 0; index--) { for (NSInteger index = [self childCountForNode:node] - 1; index >= 0;
index--) {
id<NSObject> childNode = [self childForNode:node atIndex:index]; id<NSObject> childNode = [self childForNode:node atIndex:index];
CGRect frame; CGRect frame;

View File

@@ -29,10 +29,8 @@
} }
- (NSArray<SKNamed<NSString*>*>*)attributesForNode:(UIViewController*)node { - (NSArray<SKNamed<NSString*>*>*)attributesForNode:(UIViewController*)node {
return @[ return @[ [SKNamed newWithName:@"addr"
[SKNamed newWithName: @"addr" withValue:[NSString stringWithFormat:@"%p", node]] ];
withValue: [NSString stringWithFormat: @"%p", node]]
];
} }
- (void)setHighlighted:(BOOL)highlighted forNode:(UIViewController*)node { - (void)setHighlighted:(BOOL)highlighted forNode:(UIViewController*)node {
@@ -44,7 +42,6 @@
[touch continueWithChildIndex:0 withOffset:(CGPoint){0, 0}]; [touch continueWithChildIndex:0 withOffset:(CGPoint){0, 0}];
} }
@end @end
#endif #endif

View File

@@ -9,13 +9,13 @@
#import "SKViewDescriptor.h" #import "SKViewDescriptor.h"
#import <FlipperKitHighlightOverlay/SKHighlightOverlay.h>
#import <YogaKit/UIView+Yoga.h>
#import "SKDescriptorMapper.h" #import "SKDescriptorMapper.h"
#import "SKNamed.h" #import "SKNamed.h"
#import "SKObject.h" #import "SKObject.h"
#import "SKYogaKitHelper.h" #import "SKYogaKitHelper.h"
#import "UIColor+SKSonarValueCoder.h" #import "UIColor+SKSonarValueCoder.h"
#import <YogaKit/UIView+Yoga.h>
#import <FlipperKitHighlightOverlay/SKHighlightOverlay.h>
@implementation SKViewDescriptor @implementation SKViewDescriptor
@@ -55,10 +55,12 @@ static NSDictionary *YGUnitEnumMap = nil;
// Use UIViewControllers for children which responds to a different // Use UIViewControllers for children which responds to a different
// viewController than their parent // viewController than their parent
for (UIView* child in node.subviews) { for (UIView* child in node.subviews) {
BOOL responderIsUIViewController = [child.nextResponder isKindOfClass: [UIViewController class]]; BOOL responderIsUIViewController =
[child.nextResponder isKindOfClass:[UIViewController class]];
if (!child.isHidden) { if (!child.isHidden) {
if (responderIsUIViewController && child.nextResponder != node.nextResponder) { if (responderIsUIViewController &&
child.nextResponder != node.nextResponder) {
[validChildren addObject:child.nextResponder]; [validChildren addObject:child.nextResponder];
} else { } else {
[validChildren addObject:child]; [validChildren addObject:child];
@@ -70,8 +72,10 @@ static NSDictionary *YGUnitEnumMap = nil;
} }
- (NSArray<SKNamed<NSDictionary*>*>*)dataForNode:(UIView*)node { - (NSArray<SKNamed<NSDictionary*>*>*)dataForNode:(UIView*)node {
return [NSArray arrayWithObjects: return [NSArray
[SKNamed newWithName: @"UIView" arrayWithObjects:
[SKNamed
newWithName:@"UIView"
withValue:@{ withValue:@{
@"frame" : SKMutableObject(node.frame), @"frame" : SKMutableObject(node.frame),
@"bounds" : SKObject(node.bounds), @"bounds" : SKObject(node.bounds),
@@ -82,41 +86,63 @@ static NSDictionary *YGUnitEnumMap = nil;
@"tag" : @(node.tag), @"tag" : @(node.tag),
@"backgroundColor" : SKMutableObject(node.backgroundColor) @"backgroundColor" : SKMutableObject(node.backgroundColor)
}], }],
[SKNamed newWithName: @"CALayer" [SKNamed
newWithName:@"CALayer"
withValue:@{ withValue:@{
@"shadowColor": SKMutableObject([UIColor colorWithCGColor:node.layer.shadowColor]), @"shadowColor" : SKMutableObject(
@"shadowOpacity": SKMutableObject(@(node.layer.shadowOpacity)), [UIColor colorWithCGColor:node.layer.shadowColor]),
@"shadowOpacity" :
SKMutableObject(@(node.layer.shadowOpacity)),
@"shadowRadius" : SKMutableObject(@(node.layer.shadowRadius)), @"shadowRadius" : SKMutableObject(@(node.layer.shadowRadius)),
@"shadowOffset" : SKMutableObject(node.layer.shadowOffset), @"shadowOffset" : SKMutableObject(node.layer.shadowOffset),
@"backgroundColor": SKMutableObject([UIColor colorWithCGColor:node.layer.backgroundColor]), @"backgroundColor" : SKMutableObject(
@"borderColor": SKMutableObject([UIColor colorWithCGColor:node.layer.borderColor]), [UIColor colorWithCGColor:node.layer.backgroundColor]),
@"borderColor" : SKMutableObject(
[UIColor colorWithCGColor:node.layer.borderColor]),
@"borderWidth" : SKMutableObject(@(node.layer.borderWidth)), @"borderWidth" : SKMutableObject(@(node.layer.borderWidth)),
@"cornerRadius" : SKMutableObject(@(node.layer.cornerRadius)), @"cornerRadius" : SKMutableObject(@(node.layer.cornerRadius)),
@"masksToBounds": SKMutableObject(@(node.layer.masksToBounds)), @"masksToBounds" :
SKMutableObject(@(node.layer.masksToBounds)),
}], }],
[SKNamed newWithName:@"Accessibility" [SKNamed newWithName:@"Accessibility"
withValue:@{ withValue:@{
@"isAccessibilityElement": SKMutableObject(@(node.isAccessibilityElement)), @"isAccessibilityElement" :
@"accessibilityLabel": SKMutableObject(node.accessibilityLabel ?: @""), SKMutableObject(@(node.isAccessibilityElement)),
@"accessibilityIdentifier": SKMutableObject(node.accessibilityIdentifier ?: @""), @"accessibilityLabel" :
@"accessibilityValue": SKMutableObject(node.accessibilityValue ?: @""), SKMutableObject(node.accessibilityLabel ?: @""),
@"accessibilityHint": SKMutableObject(node.accessibilityHint ?: @""), @"accessibilityIdentifier" :
@"accessibilityTraits": AccessibilityTraitsDict(node.accessibilityTraits), SKMutableObject(node.accessibilityIdentifier ?: @""),
@"accessibilityViewIsModal": SKMutableObject(@(node.accessibilityViewIsModal)), @"accessibilityValue" :
@"shouldGroupAccessibilityChildren": SKMutableObject(@(node.shouldGroupAccessibilityChildren)), SKMutableObject(node.accessibilityValue ?: @""),
@"accessibilityHint" :
SKMutableObject(node.accessibilityHint ?: @""),
@"accessibilityTraits" :
AccessibilityTraitsDict(node.accessibilityTraits),
@"accessibilityViewIsModal" :
SKMutableObject(@(node.accessibilityViewIsModal)),
@"shouldGroupAccessibilityChildren" : SKMutableObject(
@(node.shouldGroupAccessibilityChildren)),
}], }],
!node.isYogaEnabled ? nil : !node.isYogaEnabled
[SKNamed newWithName: @"YGLayout" ? nil
: [SKNamed
newWithName:@"YGLayout"
withValue:@{ withValue:@{
@"direction": SKMutableObject(YGDirectionEnumMap[@(node.yoga.direction)]), @"direction" : SKMutableObject(
@"justifyContent": SKMutableObject(YGJustifyEnumMap[@(node.yoga.justifyContent)]), YGDirectionEnumMap[@(node.yoga.direction)]),
@"justifyContent" : SKMutableObject(
YGJustifyEnumMap[@(node.yoga.justifyContent)]),
@"aligns" : @{ @"aligns" : @{
@"alignContent": SKMutableObject(YGAlignEnumMap[@(node.yoga.alignContent)]), @"alignContent" : SKMutableObject(
@"alignItems": SKMutableObject(YGAlignEnumMap[@(node.yoga.alignItems)]), YGAlignEnumMap[@(node.yoga.alignContent)]),
@"alignSelf": SKMutableObject(YGAlignEnumMap[@(node.yoga.alignSelf)]), @"alignItems" : SKMutableObject(
YGAlignEnumMap[@(node.yoga.alignItems)]),
@"alignSelf" : SKMutableObject(
YGAlignEnumMap[@(node.yoga.alignSelf)]),
}, },
@"position" : @{ @"position" : @{
@"type": SKMutableObject(YGPositionTypeEnumMap[@(node.yoga.position)]), @"type" : SKMutableObject(
YGPositionTypeEnumMap[@(node.yoga.position)]),
@"left" : SKYGValueObject(node.yoga.left), @"left" : SKYGValueObject(node.yoga.left),
@"top" : SKYGValueObject(node.yoga.top), @"top" : SKYGValueObject(node.yoga.top),
@"right" : SKYGValueObject(node.yoga.right), @"right" : SKYGValueObject(node.yoga.right),
@@ -124,13 +150,19 @@ static NSDictionary *YGUnitEnumMap = nil;
@"start" : SKYGValueObject(node.yoga.start), @"start" : SKYGValueObject(node.yoga.start),
@"end" : SKYGValueObject(node.yoga.end), @"end" : SKYGValueObject(node.yoga.end),
}, },
@"overflow": SKMutableObject(YGOverflowEnumMap[@(node.yoga.overflow)]), @"overflow" : SKMutableObject(
@"display": SKMutableObject(YGDisplayEnumMap[@(node.yoga.display)]), YGOverflowEnumMap[@(node.yoga.overflow)]),
@"display" : SKMutableObject(
YGDisplayEnumMap[@(node.yoga.display)]),
@"flex" : @{ @"flex" : @{
@"flexDirection": SKMutableObject(YGFlexDirectionEnumMap[@(node.yoga.flexDirection)]), @"flexDirection" :
@"flexWrap": SKMutableObject(YGWrapEnumMap[@(node.yoga.flexWrap)]), SKMutableObject(YGFlexDirectionEnumMap[
@(node.yoga.flexDirection)]),
@"flexWrap" : SKMutableObject(
YGWrapEnumMap[@(node.yoga.flexWrap)]),
@"flexGrow" : SKMutableObject(@(node.yoga.flexGrow)), @"flexGrow" : SKMutableObject(@(node.yoga.flexGrow)),
@"flexShrink": SKMutableObject(@(node.yoga.flexShrink)), @"flexShrink" :
SKMutableObject(@(node.yoga.flexShrink)),
@"flexBasis" : SKYGValueObject(node.yoga.flexBasis), @"flexBasis" : SKYGValueObject(node.yoga.flexBasis),
}, },
@"margin" : @{ @"margin" : @{
@@ -140,8 +172,10 @@ static NSDictionary *YGUnitEnumMap = nil;
@"bottom" : SKYGValueObject(node.yoga.marginBottom), @"bottom" : SKYGValueObject(node.yoga.marginBottom),
@"start" : SKYGValueObject(node.yoga.marginStart), @"start" : SKYGValueObject(node.yoga.marginStart),
@"end" : SKYGValueObject(node.yoga.marginEnd), @"end" : SKYGValueObject(node.yoga.marginEnd),
@"horizontal": SKYGValueObject(node.yoga.marginHorizontal), @"horizontal" :
@"vertical": SKYGValueObject(node.yoga.marginVertical), SKYGValueObject(node.yoga.marginHorizontal),
@"vertical" :
SKYGValueObject(node.yoga.marginVertical),
@"all" : SKYGValueObject(node.yoga.margin), @"all" : SKYGValueObject(node.yoga.margin),
}, },
@"padding" : @{ @"padding" : @{
@@ -151,17 +185,25 @@ static NSDictionary *YGUnitEnumMap = nil;
@"bottom" : SKYGValueObject(node.yoga.paddingBottom), @"bottom" : SKYGValueObject(node.yoga.paddingBottom),
@"start" : SKYGValueObject(node.yoga.paddingStart), @"start" : SKYGValueObject(node.yoga.paddingStart),
@"end" : SKYGValueObject(node.yoga.paddingEnd), @"end" : SKYGValueObject(node.yoga.paddingEnd),
@"horizontal": SKYGValueObject(node.yoga.paddingHorizontal), @"horizontal" :
@"vertical": SKYGValueObject(node.yoga.paddingVertical), SKYGValueObject(node.yoga.paddingHorizontal),
@"vertical" :
SKYGValueObject(node.yoga.paddingVertical),
@"all" : SKYGValueObject(node.yoga.padding), @"all" : SKYGValueObject(node.yoga.padding),
}, },
@"border" : @{ @"border" : @{
@"leftWidth": SKMutableObject(@(node.yoga.borderLeftWidth)), @"leftWidth" :
@"topWidth": SKMutableObject(@(node.yoga.borderTopWidth)), SKMutableObject(@(node.yoga.borderLeftWidth)),
@"rightWidth": SKMutableObject(@(node.yoga.borderRightWidth)), @"topWidth" :
@"bottomWidth": SKMutableObject(@(node.yoga.borderBottomWidth)), SKMutableObject(@(node.yoga.borderTopWidth)),
@"startWidth": SKMutableObject(@(node.yoga.borderStartWidth)), @"rightWidth" :
@"endWidth": SKMutableObject(@(node.yoga.borderEndWidth)), SKMutableObject(@(node.yoga.borderRightWidth)),
@"bottomWidth" :
SKMutableObject(@(node.yoga.borderBottomWidth)),
@"startWidth" :
SKMutableObject(@(node.yoga.borderStartWidth)),
@"endWidth" :
SKMutableObject(@(node.yoga.borderEndWidth)),
@"all" : SKMutableObject(@(node.yoga.borderWidth)), @"all" : SKMutableObject(@(node.yoga.borderWidth)),
}, },
@"dimensions" : @{ @"dimensions" : @{
@@ -172,18 +214,22 @@ static NSDictionary *YGUnitEnumMap = nil;
@"maxWidth" : SKYGValueObject(node.yoga.maxWidth), @"maxWidth" : SKYGValueObject(node.yoga.maxWidth),
@"maxHeight" : SKYGValueObject(node.yoga.maxHeight), @"maxHeight" : SKYGValueObject(node.yoga.maxHeight),
}, },
@"aspectRatio": SKMutableObject(@(node.yoga.aspectRatio)), @"aspectRatio" :
@"resolvedDirection": SKObject(YGDirectionEnumMap[@(node.yoga.resolvedDirection)]), SKMutableObject(@(node.yoga.aspectRatio)),
@"resolvedDirection" : SKObject(
YGDirectionEnumMap[@(node.yoga.resolvedDirection)]),
}], }],
nil]; nil];
} }
- (NSDictionary<NSString *, SKNodeUpdateData> *)dataMutationsForNode:(UIView *)node { - (NSDictionary<NSString*, SKNodeUpdateData>*)dataMutationsForNode:
(UIView*)node {
return @{ return @{
// UIView // UIView
@"UIView.alpha" : ^(NSNumber* value){ @"UIView.alpha" : ^(NSNumber* value){
node.alpha = [value floatValue]; node.alpha = [value floatValue];
}, }
,
@"UIView.backgroundColor": ^(NSNumber *value) { @"UIView.backgroundColor": ^(NSNumber *value) {
node.backgroundColor = [UIColor fromSonarValue: value]; node.backgroundColor = [UIColor fromSonarValue: value];
}, },
@@ -415,14 +461,13 @@ static NSDictionary *YGUnitEnumMap = nil;
@"Accessibility.shouldGroupAccessibilityChildren": ^(NSNumber *value) { @"Accessibility.shouldGroupAccessibilityChildren": ^(NSNumber *value) {
node.shouldGroupAccessibilityChildren = [value boolValue]; node.shouldGroupAccessibilityChildren = [value boolValue];
}, },
}; }
;
} }
- (NSArray<SKNamed<NSString*>*>*)attributesForNode:(UIView*)node { - (NSArray<SKNamed<NSString*>*>*)attributesForNode:(UIView*)node {
return @[ return @[ [SKNamed newWithName:@"addr"
[SKNamed newWithName: @"addr" withValue:[NSString stringWithFormat:@"%p", node]] ];
withValue: [NSString stringWithFormat: @"%p", node]]
];
} }
- (void)setHighlighted:(BOOL)highlighted forNode:(UIView*)node { - (void)setHighlighted:(BOOL)highlighted forNode:(UIView*)node {
@@ -435,7 +480,8 @@ static NSDictionary *YGUnitEnumMap = nil;
} }
- (void)hitTest:(SKTouch*)touch forNode:(UIView*)node { - (void)hitTest:(SKTouch*)touch forNode:(UIView*)node {
for (NSInteger index = [self childCountForNode: node] - 1; index >= 0; index--) { for (NSInteger index = [self childCountForNode:node] - 1; index >= 0;
index--) {
id<NSObject> childNode = [self childForNode:node atIndex:index]; id<NSObject> childNode = [self childForNode:node atIndex:index];
UIView* viewForNode = nil; UIView* viewForNode = nil;
@@ -537,36 +583,60 @@ static NSDictionary *SKYGValueObject(YGValue value) {
e.g. originalTraits = UIAccessibilityTraitButton | UIAccessibilityTraitSelected e.g. originalTraits = UIAccessibilityTraitButton | UIAccessibilityTraitSelected
toggleTraits = UIAccessibilityTraitImage toggleTraits = UIAccessibilityTraitImage
toggleValue = YES toggleValue = YES
return value = UIAccessibilityTraitButton | UIAccessibilityTraitSelected | UIAccessibilityTraitImage return value = UIAccessibilityTraitButton | UIAccessibilityTraitSelected |
UIAccessibilityTraitImage
*/ */
static UIAccessibilityTraits AccessibilityTraitsToggle(UIAccessibilityTraits originalTraits, UIAccessibilityTraits toggleTraits, BOOL toggleValue) { static UIAccessibilityTraits AccessibilityTraitsToggle(
// NEGATE all bits of toggleTraits from originalTraits and OR it against either toggleTraits or 0 (UIAccessibilityTraitNone) based on toggleValue UIAccessibilityTraits originalTraits,
UIAccessibilityTraits bitsValue = toggleValue ? toggleTraits : UIAccessibilityTraitNone; UIAccessibilityTraits toggleTraits,
BOOL toggleValue) {
// NEGATE all bits of toggleTraits from originalTraits and OR it against
// either toggleTraits or 0 (UIAccessibilityTraitNone) based on toggleValue
UIAccessibilityTraits bitsValue =
toggleValue ? toggleTraits : UIAccessibilityTraitNone;
return (originalTraits & ~(toggleTraits)) | bitsValue; return (originalTraits & ~(toggleTraits)) | bitsValue;
} }
static NSDictionary *AccessibilityTraitsDict(UIAccessibilityTraits accessibilityTraits) { static NSDictionary* AccessibilityTraitsDict(
UIAccessibilityTraits accessibilityTraits) {
NSMutableDictionary* traitsDict = [NSMutableDictionary new]; NSMutableDictionary* traitsDict = [NSMutableDictionary new];
[traitsDict addEntriesFromDictionary:@{ [traitsDict addEntriesFromDictionary:@{
@"UIAccessibilityTraitButton": SKMutableObject(@(!!(accessibilityTraits & UIAccessibilityTraitButton))), @"UIAccessibilityTraitButton" : SKMutableObject(
@"UIAccessibilityTraitLink": SKMutableObject(@(!!(accessibilityTraits & UIAccessibilityTraitLink))), @(!!(accessibilityTraits & UIAccessibilityTraitButton))),
@"UIAccessibilityTraitHeader": SKMutableObject(@(!!(accessibilityTraits & UIAccessibilityTraitHeader))), @"UIAccessibilityTraitLink" :
@"UIAccessibilityTraitSearchField": SKMutableObject(@(!!(accessibilityTraits & UIAccessibilityTraitSearchField))), SKMutableObject(@(!!(accessibilityTraits & UIAccessibilityTraitLink))),
@"UIAccessibilityTraitImage": SKMutableObject(@(!!(accessibilityTraits & UIAccessibilityTraitImage))), @"UIAccessibilityTraitHeader" : SKMutableObject(
@"UIAccessibilityTraitSelected": SKMutableObject(@(!!(accessibilityTraits & UIAccessibilityTraitSelected))), @(!!(accessibilityTraits & UIAccessibilityTraitHeader))),
@"UIAccessibilityTraitPlaysSound": SKMutableObject(@(!!(accessibilityTraits & UIAccessibilityTraitPlaysSound))), @"UIAccessibilityTraitSearchField" : SKMutableObject(
@"UIAccessibilityTraitKeyboardKey": SKMutableObject(@(!!(accessibilityTraits & UIAccessibilityTraitKeyboardKey))), @(!!(accessibilityTraits & UIAccessibilityTraitSearchField))),
@"UIAccessibilityTraitStaticText": SKMutableObject(@(!!(accessibilityTraits & UIAccessibilityTraitStaticText))), @"UIAccessibilityTraitImage" :
@"UIAccessibilityTraitSummaryElement": SKMutableObject(@(!!(accessibilityTraits & UIAccessibilityTraitSummaryElement))), SKMutableObject(@(!!(accessibilityTraits & UIAccessibilityTraitImage))),
@"UIAccessibilityTraitNotEnabled": SKMutableObject(@(!!(accessibilityTraits & UIAccessibilityTraitNotEnabled))), @"UIAccessibilityTraitSelected" : SKMutableObject(
@"UIAccessibilityTraitUpdatesFrequently": SKMutableObject(@(!!(accessibilityTraits & UIAccessibilityTraitUpdatesFrequently))), @(!!(accessibilityTraits & UIAccessibilityTraitSelected))),
@"UIAccessibilityTraitStartsMediaSession": SKMutableObject(@(!!(accessibilityTraits & UIAccessibilityTraitStartsMediaSession))), @"UIAccessibilityTraitPlaysSound" : SKMutableObject(
@"UIAccessibilityTraitAdjustable": SKMutableObject(@(!!(accessibilityTraits & UIAccessibilityTraitAdjustable))), @(!!(accessibilityTraits & UIAccessibilityTraitPlaysSound))),
@"UIAccessibilityTraitAllowsDirectInteraction": SKMutableObject(@(!!(accessibilityTraits & UIAccessibilityTraitAllowsDirectInteraction))), @"UIAccessibilityTraitKeyboardKey" : SKMutableObject(
@"UIAccessibilityTraitCausesPageTurn": SKMutableObject(@(!!(accessibilityTraits & UIAccessibilityTraitCausesPageTurn))), @(!!(accessibilityTraits & UIAccessibilityTraitKeyboardKey))),
@"UIAccessibilityTraitStaticText" : SKMutableObject(
@(!!(accessibilityTraits & UIAccessibilityTraitStaticText))),
@"UIAccessibilityTraitSummaryElement" : SKMutableObject(
@(!!(accessibilityTraits & UIAccessibilityTraitSummaryElement))),
@"UIAccessibilityTraitNotEnabled" : SKMutableObject(
@(!!(accessibilityTraits & UIAccessibilityTraitNotEnabled))),
@"UIAccessibilityTraitUpdatesFrequently" : SKMutableObject(
@(!!(accessibilityTraits & UIAccessibilityTraitUpdatesFrequently))),
@"UIAccessibilityTraitStartsMediaSession" : SKMutableObject(
@(!!(accessibilityTraits & UIAccessibilityTraitStartsMediaSession))),
@"UIAccessibilityTraitAdjustable" : SKMutableObject(
@(!!(accessibilityTraits & UIAccessibilityTraitAdjustable))),
@"UIAccessibilityTraitAllowsDirectInteraction" : SKMutableObject(@(
!!(accessibilityTraits & UIAccessibilityTraitAllowsDirectInteraction))),
@"UIAccessibilityTraitCausesPageTurn" : SKMutableObject(
@(!!(accessibilityTraits & UIAccessibilityTraitCausesPageTurn))),
}]; }];
if (@available(iOS 10.0, *)) { if (@available(iOS 10.0, *)) {
traitsDict[@"UIAccessibilityTraitTabBar"] = SKMutableObject(@(!!(accessibilityTraits & UIAccessibilityTraitTabBar))); traitsDict[@"UIAccessibilityTraitTabBar"] = SKMutableObject(
@(!!(accessibilityTraits & UIAccessibilityTraitTabBar)));
} }
return traitsDict; return traitsDict;
} }

View File

@@ -16,12 +16,16 @@ void swizzleMethods(Class cls, SEL original, SEL swissled) {
Method originalMethod = class_getInstanceMethod(cls, original); Method originalMethod = class_getInstanceMethod(cls, original);
Method swissledMethod = class_getInstanceMethod(cls, swissled); Method swissledMethod = class_getInstanceMethod(cls, swissled);
BOOL didAddMethod = class_addMethod(cls, original, BOOL didAddMethod = class_addMethod(
cls,
original,
method_getImplementation(swissledMethod), method_getImplementation(swissledMethod),
method_getTypeEncoding(swissledMethod)); method_getTypeEncoding(swissledMethod));
if (didAddMethod) { if (didAddMethod) {
class_replaceMethod(cls, swissled, class_replaceMethod(
cls,
swissled,
method_getImplementation(originalMethod), method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod)); method_getTypeEncoding(originalMethod));
} else { } else {

View File

@@ -9,8 +9,11 @@
#define APPLY_ENUM_TO_YOGA_PROPERTY(varName, enumName) \ #define APPLY_ENUM_TO_YOGA_PROPERTY(varName, enumName) \
^(NSString * newValue) { \ ^(NSString * newValue) { \
NSNumber *varName = [[enumName##EnumMap allKeysForObject:newValue] lastObject]; \ NSNumber* varName = \
if (varName == nil) { return; } \ [[enumName##EnumMap allKeysForObject:newValue] lastObject]; \
if (varName == nil) { \
return; \
} \
node.yoga.varName = (enumName)[varName unsignedIntegerValue]; \ node.yoga.varName = (enumName)[varName unsignedIntegerValue]; \
} }
@@ -23,8 +26,11 @@ node.yoga.varName = newValue; \
#define APPLY_UNIT_TO_YGVALUE(varName, enumName) \ #define APPLY_UNIT_TO_YGVALUE(varName, enumName) \
^(NSString * value) { \ ^(NSString * value) { \
NSNumber *varName = [[enumName##EnumMap allKeysForObject:value] lastObject]; \ NSNumber* varName = \
if (varName == nil) { return; } \ [[enumName##EnumMap allKeysForObject:value] lastObject]; \
if (varName == nil) { \
return; \
} \
YGValue newValue = node.yoga.varName; \ YGValue newValue = node.yoga.varName; \
newValue.unit = (enumName)[varName unsignedIntegerValue]; \ newValue.unit = (enumName)[varName unsignedIntegerValue]; \
node.yoga.varName = newValue; \ node.yoga.varName = newValue; \

View File

@@ -7,8 +7,7 @@
#import "SKTapListenerMock.h" #import "SKTapListenerMock.h"
@implementation SKTapListenerMock @implementation SKTapListenerMock {
{
NSMutableArray<SKTapReceiver>* _tapReceivers; NSMutableArray<SKTapReceiver>* _tapReceivers;
} }

View File

@@ -9,9 +9,9 @@
#if FB_SONARKIT_ENABLED #if FB_SONARKIT_ENABLED
#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
#import <FlipperKitLayoutPlugin/SKDescriptorMapper.h> #import <FlipperKitLayoutPlugin/SKDescriptorMapper.h>
#import <FlipperKitLayoutPlugin/SKNodeDescriptor.h> #import <FlipperKitLayoutPlugin/SKNodeDescriptor.h>
#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
#import <FlipperKitTestUtils/FlipperConnectionMock.h> #import <FlipperKitTestUtils/FlipperConnectionMock.h>
#import <FlipperKitTestUtils/FlipperResponderMock.h> #import <FlipperKitTestUtils/FlipperResponderMock.h>
@@ -22,8 +22,7 @@
@interface SonarKitLayoutPluginTests : XCTestCase @interface SonarKitLayoutPluginTests : XCTestCase
@end @end
@implementation SonarKitLayoutPluginTests @implementation SonarKitLayoutPluginTests {
{
SKDescriptorMapper* _descriptorMapper; SKDescriptorMapper* _descriptorMapper;
} }
@@ -81,7 +80,8 @@
rootNode.children = childNodes; rootNode.children = childNodes;
FlipperKitLayoutPlugin *plugin = [[FlipperKitLayoutPlugin alloc] initWithRootNode: rootNode FlipperKitLayoutPlugin* plugin =
[[FlipperKitLayoutPlugin alloc] initWithRootNode:rootNode
withTapListener:nil withTapListener:nil
withDescriptorMapper:_descriptorMapper]; withDescriptorMapper:_descriptorMapper];
@@ -93,9 +93,11 @@
connection.receivers[@"getRoot"](@{}, responder); connection.receivers[@"getRoot"](@{}, responder);
SonarReceiver receiver = connection.receivers[@"getNodes"]; SonarReceiver receiver = connection.receivers[@"getNodes"];
receiver(@{@"ids": @[ @"testNode1", @"testNode2", @"testNode3" ]}, responder); receiver(
@{@"ids" : @[ @"testNode1", @"testNode2", @"testNode3" ]}, responder);
XCTAssertTrue(([responder.successes containsObject:@{@"elements": @[ XCTAssertTrue(([responder.successes containsObject:@{
@"elements" : @[
@{ @{
@"id" : @"testNode1", @"id" : @"testNode1",
@"name" : @"TestNode", @"name" : @"TestNode",
@@ -120,7 +122,8 @@
@"data" : @{}, @"data" : @{},
@"decoration" : @"", @"decoration" : @"",
}, },
]}])); ]
}]));
} }
- (void)testSetHighlighted { - (void)testSetHighlighted {
@@ -132,7 +135,8 @@
rootNode.children = childNodes; rootNode.children = childNodes;
FlipperKitLayoutPlugin *plugin = [[FlipperKitLayoutPlugin alloc] initWithRootNode: rootNode FlipperKitLayoutPlugin* plugin =
[[FlipperKitLayoutPlugin alloc] initWithRootNode:rootNode
withTapListener:nil withTapListener:nil
withDescriptorMapper:_descriptorMapper]; withDescriptorMapper:_descriptorMapper];
@@ -160,18 +164,22 @@
TestNode* rootNode = [[TestNode alloc] initWithName:@"rootNode" TestNode* rootNode = [[TestNode alloc] initWithName:@"rootNode"
withFrame:CGRectMake(0, 0, 20, 60)]; withFrame:CGRectMake(0, 0, 20, 60)];
TestNode *testNode1 = [[TestNode alloc] initWithName: @"testNode1" TestNode* testNode1 =
[[TestNode alloc] initWithName:@"testNode1"
withFrame:CGRectMake(20, 20, 20, 20)]; withFrame:CGRectMake(20, 20, 20, 20)];
TestNode *testNode2 = [[TestNode alloc] initWithName: @"testNode2" TestNode* testNode2 =
[[TestNode alloc] initWithName:@"testNode2"
withFrame:CGRectMake(20, 40, 20, 20)]; withFrame:CGRectMake(20, 40, 20, 20)];
TestNode *testNode3 = [[TestNode alloc] initWithName: @"testNode3" TestNode* testNode3 =
[[TestNode alloc] initWithName:@"testNode3"
withFrame:CGRectMake(25, 42, 5, 5)]; withFrame:CGRectMake(25, 42, 5, 5)];
rootNode.children = @[ testNode1, testNode2 ]; rootNode.children = @[ testNode1, testNode2 ];
testNode2.children = @[ testNode3 ]; testNode2.children = @[ testNode3 ];
SKTapListenerMock* tapListener = [SKTapListenerMock new]; SKTapListenerMock* tapListener = [SKTapListenerMock new];
FlipperKitLayoutPlugin *plugin = [[FlipperKitLayoutPlugin alloc] initWithRootNode: rootNode FlipperKitLayoutPlugin* plugin =
[[FlipperKitLayoutPlugin alloc] initWithRootNode:rootNode
withTapListener:tapListener withTapListener:tapListener
withDescriptorMapper:_descriptorMapper]; withDescriptorMapper:_descriptorMapper];
@@ -184,14 +192,16 @@
// Fake a tap at `testNode3` // Fake a tap at `testNode3`
[tapListener tapAt:(CGPoint){26, 43}]; [tapListener tapAt:(CGPoint){26, 43}];
XCTAssertTrue(([connection.sent[@"select"] containsObject: @{ @"path": @[ @"testNode2", @"testNode3" ] }])); XCTAssertTrue(([connection.sent[@"select"]
containsObject:@{@"path" : @[ @"testNode2", @"testNode3" ]}]));
} }
- (void)testSetSearchActiveMountAndUnmount { - (void)testSetSearchActiveMountAndUnmount {
TestNode* rootNode = [[TestNode alloc] initWithName:@"rootNode"]; TestNode* rootNode = [[TestNode alloc] initWithName:@"rootNode"];
SKTapListenerMock* tapListener = [SKTapListenerMock new]; SKTapListenerMock* tapListener = [SKTapListenerMock new];
FlipperKitLayoutPlugin *plugin = [[FlipperKitLayoutPlugin alloc] initWithRootNode: rootNode FlipperKitLayoutPlugin* plugin =
[[FlipperKitLayoutPlugin alloc] initWithRootNode:rootNode
withTapListener:tapListener withTapListener:tapListener
withDescriptorMapper:_descriptorMapper]; withDescriptorMapper:_descriptorMapper];
@@ -212,18 +222,22 @@
TestNode* rootNode = [[TestNode alloc] initWithName:@"rootNode" TestNode* rootNode = [[TestNode alloc] initWithName:@"rootNode"
withFrame:CGRectMake(0, 0, 20, 60)]; withFrame:CGRectMake(0, 0, 20, 60)];
TestNode *testNode1 = [[TestNode alloc] initWithName: @"testNode1" TestNode* testNode1 =
[[TestNode alloc] initWithName:@"testNode1"
withFrame:CGRectMake(20, 20, 20, 20)]; withFrame:CGRectMake(20, 20, 20, 20)];
TestNode *testNode2 = [[TestNode alloc] initWithName: @"testNode2" TestNode* testNode2 =
[[TestNode alloc] initWithName:@"testNode2"
withFrame:CGRectMake(20, 40, 20, 20)]; withFrame:CGRectMake(20, 40, 20, 20)];
TestNode *testNode3 = [[TestNode alloc] initWithName: @"testNode3" TestNode* testNode3 =
[[TestNode alloc] initWithName:@"testNode3"
withFrame:CGRectMake(25, 42, 5, 5)]; withFrame:CGRectMake(25, 42, 5, 5)];
rootNode.children = @[ testNode1, testNode2 ]; rootNode.children = @[ testNode1, testNode2 ];
testNode2.children = @[ testNode3 ]; testNode2.children = @[ testNode3 ];
SKTapListenerMock* tapListener = [SKTapListenerMock new]; SKTapListenerMock* tapListener = [SKTapListenerMock new];
FlipperKitLayoutPlugin *plugin = [[FlipperKitLayoutPlugin alloc] initWithRootNode: rootNode FlipperKitLayoutPlugin* plugin =
[[FlipperKitLayoutPlugin alloc] initWithRootNode:rootNode
withTapListener:tapListener withTapListener:tapListener
withDescriptorMapper:_descriptorMapper]; withDescriptorMapper:_descriptorMapper];
@@ -236,13 +250,16 @@
connection.receivers[@"getNodes"](@{@"ids" : @[ @"testNode2" ]}, responder); connection.receivers[@"getNodes"](@{@"ids" : @[ @"testNode2" ]}, responder);
// Modify the name of testNode3 // Modify the name of testNode3
connection.receivers[@"setData"](@{ connection.receivers[@"setData"](
@{
@"id" : @"testNode3", @"id" : @"testNode3",
@"path" : @[ @"TestNode", @"name" ], @"path" : @[ @"TestNode", @"name" ],
@"value" : @"changedNameForTestNode3", @"value" : @"changedNameForTestNode3",
}, responder); },
responder);
XCTAssertTrue([testNode3.nodeName isEqualToString: @"changedNameForTestNode3"]); XCTAssertTrue(
[testNode3.nodeName isEqualToString:@"changedNameForTestNode3"]);
} }
@end @end

View File

@@ -10,8 +10,7 @@
@implementation TestNode @implementation TestNode
- (instancetype)initWithName:(NSString*)name { - (instancetype)initWithName:(NSString*)name {
return [self initWithName: name return [self initWithName:name withFrame:CGRectZero];
withFrame: CGRectZero];
} }
- (instancetype)initWithName:(NSString*)name withFrame:(CGRect)frame { - (instancetype)initWithName:(NSString*)name withFrame:(CGRect)frame {

View File

@@ -39,12 +39,13 @@
[touch finish]; [touch finish];
} }
- (NSDictionary<NSString *, SKNodeUpdateData> *)dataMutationsForNode:(TestNode *)node { - (NSDictionary<NSString*, SKNodeUpdateData>*)dataMutationsForNode:
return @{ (TestNode*)node {
@"TestNode.name": ^(NSString *newName) { return @{@"TestNode.name" : ^(NSString* newName){
node.nodeName = newName; node.nodeName = newName;
} }
}; }
;
} }
@end @end

View File

@@ -13,10 +13,14 @@
#import "SKBufferingPlugin.h" #import "SKBufferingPlugin.h"
#import "SKNetworkReporter.h" #import "SKNetworkReporter.h"
@interface FlipperKitNetworkPlugin : SKBufferingPlugin <SKNetworkReporterDelegate> @interface FlipperKitNetworkPlugin
: SKBufferingPlugin<SKNetworkReporterDelegate>
- (instancetype)initWithNetworkAdapter:(id<SKNetworkAdapterDelegate>)adapter NS_DESIGNATED_INITIALIZER; - (instancetype)initWithNetworkAdapter:(id<SKNetworkAdapterDelegate>)adapter
- (instancetype)initWithNetworkAdapter:(id<SKNetworkAdapterDelegate>)adapter queue:(dispatch_queue_t)queue; //For test purposes NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithNetworkAdapter:(id<SKNetworkAdapterDelegate>)adapter
queue:(dispatch_queue_t)
queue; // For test purposes
@property(strong, nonatomic) id<SKNetworkAdapterDelegate> adapter; @property(strong, nonatomic) id<SKNetworkAdapterDelegate> adapter;

View File

@@ -6,14 +6,14 @@
*/ */
#if FB_SONARKIT_ENABLED #if FB_SONARKIT_ENABLED
#import <vector> #import "FlipperKitNetworkPlugin.h"
#import <iostream> #import <iostream>
#import <memory> #import <memory>
#import "FlipperKitNetworkPlugin.h" #import <vector>
#import "SKNetworkReporter.h"
#import "SonarKitNetworkPlugin+CPPInitialization.h"
#import "SKBufferingPlugin+CPPInitialization.h" #import "SKBufferingPlugin+CPPInitialization.h"
#import "SKDispatchQueue.h" #import "SKDispatchQueue.h"
#import "SKNetworkReporter.h"
#import "SonarKitNetworkPlugin+CPPInitialization.h"
@interface FlipperKitNetworkPlugin () @interface FlipperKitNetworkPlugin ()
@@ -27,20 +27,26 @@
} }
- (instancetype)init { - (instancetype)init {
if (self = [super initWithQueue:dispatch_queue_create("com.sonarkit.network.buffer", DISPATCH_QUEUE_SERIAL)]) { if (self = [super initWithQueue:dispatch_queue_create(
"com.sonarkit.network.buffer",
DISPATCH_QUEUE_SERIAL)]) {
} }
return self; return self;
} }
- (instancetype)initWithNetworkAdapter:(id<SKNetworkAdapterDelegate>)adapter { - (instancetype)initWithNetworkAdapter:(id<SKNetworkAdapterDelegate>)adapter {
if (self = [super initWithQueue:dispatch_queue_create("com.sonarkit.network.buffer", DISPATCH_QUEUE_SERIAL)]) { if (self = [super initWithQueue:dispatch_queue_create(
"com.sonarkit.network.buffer",
DISPATCH_QUEUE_SERIAL)]) {
adapter.delegate = self; adapter.delegate = self;
_adapter = adapter; _adapter = adapter;
} }
return self; return self;
} }
- (instancetype)initWithNetworkAdapter:(id<SKNetworkAdapterDelegate>)adapter queue:(dispatch_queue_t)queue; { - (instancetype)initWithNetworkAdapter:(id<SKNetworkAdapterDelegate>)adapter
queue:(dispatch_queue_t)queue;
{
if (self = [super initWithQueue:queue]) { if (self = [super initWithQueue:queue]) {
adapter.delegate = self; adapter.delegate = self;
_adapter = adapter; _adapter = adapter;
@@ -50,15 +56,11 @@
#pragma mark - SKNetworkReporterDelegate #pragma mark - SKNetworkReporterDelegate
- (void)didObserveRequest:(SKRequestInfo*)request {
- (void)didObserveRequest:(SKRequestInfo *)request
{
NSMutableArray<NSDictionary<NSString*, id>*>* headers = [NSMutableArray new]; NSMutableArray<NSDictionary<NSString*, id>*>* headers = [NSMutableArray new];
for (NSString* key in [request.request.allHTTPHeaderFields allKeys]) { for (NSString* key in [request.request.allHTTPHeaderFields allKeys]) {
NSDictionary<NSString *, id> *header = @{ NSDictionary<NSString*, id>* header =
@"key": key, @{@"key" : key, @"value" : request.request.allHTTPHeaderFields[key]};
@"value": request.request.allHTTPHeaderFields[key]
};
[headers addObject:header]; [headers addObject:header];
} }
@@ -75,16 +77,13 @@
}]; }];
} }
- (void)didObserveResponse:(SKResponseInfo *)response - (void)didObserveResponse:(SKResponseInfo*)response {
{
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response.response; NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response.response;
NSMutableArray<NSDictionary<NSString*, id>*>* headers = [NSMutableArray new]; NSMutableArray<NSDictionary<NSString*, id>*>* headers = [NSMutableArray new];
for (NSString* key in [httpResponse.allHeaderFields allKeys]) { for (NSString* key in [httpResponse.allHeaderFields allKeys]) {
NSDictionary<NSString *, id> *header = @{ NSDictionary<NSString*, id>* header =
@"key": key, @{@"key" : key, @"value" : httpResponse.allHeaderFields[key]};
@"value": httpResponse.allHeaderFields[key]
};
[headers addObject:header]; [headers addObject:header];
} }
@@ -95,18 +94,22 @@
@"id" : @(response.identifier), @"id" : @(response.identifier),
@"timestamp" : @(response.timestamp), @"timestamp" : @(response.timestamp),
@"status" : @(httpResponse.statusCode), @"status" : @(httpResponse.statusCode),
@"reason": [NSHTTPURLResponse localizedStringForStatusCode: httpResponse.statusCode] ?: [NSNull null], @"reason" : [NSHTTPURLResponse
localizedStringForStatusCode:httpResponse.statusCode]
?: [NSNull null],
@"headers" : headers, @"headers" : headers,
@"data" : body ? body : [NSNull null] @"data" : body ? body : [NSNull null]
}]; }];
} }
@end @end
@implementation FlipperKitNetworkPlugin (CPPInitialization) @implementation FlipperKitNetworkPlugin (CPPInitialization)
- (instancetype)initWithNetworkAdapter:(id<SKNetworkAdapterDelegate>)adapter dispatchQueue:(std::shared_ptr<facebook::flipper::DispatchQueue>)queue { - (instancetype)initWithNetworkAdapter:(id<SKNetworkAdapterDelegate>)adapter
dispatchQueue:
(std::shared_ptr<facebook::flipper::DispatchQueue>)
queue {
if (self = [super initWithDispatchQueue:queue]) { if (self = [super initWithDispatchQueue:queue]) {
adapter.delegate = self; adapter.delegate = self;
_adapter = adapter; _adapter = adapter;

View File

@@ -8,21 +8,24 @@
#if FB_SONARKIT_ENABLED #if FB_SONARKIT_ENABLED
#pragma once #pragma once
#import "SKBufferingPlugin.h"
#import "SKDispatchQueue.h"
#import <iostream> #import <iostream>
#import <memory> #import <memory>
#import "SKBufferingPlugin.h"
#import "SKDispatchQueue.h"
struct CachedEvent { struct CachedEvent {
NSString* method; NSString* method;
NSDictionary<NSString*, id>* sonarObject; NSDictionary<NSString*, id>* sonarObject;
}; };
@interface SKBufferingPlugin (CPPInitialization) @interface SKBufferingPlugin (CPPInitialization)
- (instancetype)initWithVectorEventSize:(NSUInteger)size connectionAccessQueue:(std::shared_ptr<facebook::flipper::DispatchQueue>)connectionAccessQueue; - (instancetype)initWithVectorEventSize:(NSUInteger)size
- (instancetype)initWithDispatchQueue:(std::shared_ptr<facebook::flipper::DispatchQueue>)queue; connectionAccessQueue:
(std::shared_ptr<facebook::flipper::DispatchQueue>)
connectionAccessQueue;
- (instancetype)initWithDispatchQueue:
(std::shared_ptr<facebook::flipper::DispatchQueue>)queue;
@end @end

View File

@@ -15,7 +15,8 @@
- (instancetype)initWithQueue:(dispatch_queue_t)queue NS_DESIGNATED_INITIALIZER; - (instancetype)initWithQueue:(dispatch_queue_t)queue NS_DESIGNATED_INITIALIZER;
- (void)send:(NSString *)method sonarObject:(NSDictionary<NSString *, id> *)sonarObject; - (void)send:(NSString*)method
sonarObject:(NSDictionary<NSString*, id>*)sonarObject;
@end @end

View File

@@ -9,17 +9,18 @@
#import <vector> #import <vector>
#import "SKBufferingPlugin.h"
#import <FlipperKit/FlipperConnection.h> #import <FlipperKit/FlipperConnection.h>
#import "SKDispatchQueue.h"
#import "SKBufferingPlugin+CPPInitialization.h" #import "SKBufferingPlugin+CPPInitialization.h"
#import "SKBufferingPlugin.h"
#import "SKDispatchQueue.h"
static const NSUInteger bufferSize = 500; static const NSUInteger bufferSize = 500;
@interface SKBufferingPlugin () @interface SKBufferingPlugin ()
@property(assign, nonatomic) std::vector<CachedEvent> ringBuffer; @property(assign, nonatomic) std::vector<CachedEvent> ringBuffer;
@property(assign, nonatomic) std::shared_ptr<facebook::flipper::DispatchQueue> connectionAccessQueue; @property(assign, nonatomic) std::shared_ptr<facebook::flipper::DispatchQueue>
connectionAccessQueue;
@property(strong, nonatomic) id<FlipperConnection> connection; @property(strong, nonatomic) id<FlipperConnection> connection;
@end @end
@@ -35,7 +36,8 @@ static const NSUInteger bufferSize = 500;
- (instancetype)initWithQueue:(dispatch_queue_t)queue { - (instancetype)initWithQueue:(dispatch_queue_t)queue {
if (self = [super init]) { if (self = [super init]) {
_ringBuffer.reserve(bufferSize); _ringBuffer.reserve(bufferSize);
_connectionAccessQueue = std::make_shared<facebook::flipper::GCDQueue>(queue); _connectionAccessQueue =
std::make_shared<facebook::flipper::GCDQueue>(queue);
} }
return self; return self;
} }
@@ -62,7 +64,6 @@ static const NSUInteger bufferSize = 500;
return YES; return YES;
} }
- (void)send:(NSString*)method - (void)send:(NSString*)method
sonarObject:(NSDictionary<NSString*, id>*)sonarObject { sonarObject:(NSDictionary<NSString*, id>*)sonarObject {
_connectionAccessQueue->async(^{ _connectionAccessQueue->async(^{
@@ -72,10 +73,8 @@ static const NSUInteger bufferSize = 500;
if (self->_ringBuffer.size() == bufferSize) { if (self->_ringBuffer.size() == bufferSize) {
return; return;
} }
self->_ringBuffer.push_back({ self->_ringBuffer.push_back(
.method = method, {.method = method, .sonarObject = sonarObject});
.sonarObject = sonarObject
});
} }
}); });
} }
@@ -92,20 +91,21 @@ static const NSUInteger bufferSize = 500;
@implementation SKBufferingPlugin (CPPInitialization) @implementation SKBufferingPlugin (CPPInitialization)
- (instancetype)initWithVectorEventSize:(NSUInteger)size connectionAccessQueue:(std::shared_ptr<facebook::flipper::DispatchQueue>)connectionAccessQueue { - (instancetype)initWithVectorEventSize:(NSUInteger)size
connectionAccessQueue:
(std::shared_ptr<facebook::flipper::DispatchQueue>)
connectionAccessQueue {
if (self = [super init]) { if (self = [super init]) {
_ringBuffer.reserve(size); _ringBuffer.reserve(size);
_connectionAccessQueue = connectionAccessQueue; _connectionAccessQueue = connectionAccessQueue;
} }
return self; return self;
} }
- (instancetype)initWithDispatchQueue:(std::shared_ptr<facebook::flipper::DispatchQueue>)queue { - (instancetype)initWithDispatchQueue:
return [self initWithVectorEventSize:bufferSize (std::shared_ptr<facebook::flipper::DispatchQueue>)queue {
connectionAccessQueue:queue]; return [self initWithVectorEventSize:bufferSize connectionAccessQueue:queue];
} }
@end @end
#endif #endif

View File

@@ -13,21 +13,18 @@
namespace facebook { namespace facebook {
namespace flipper { namespace flipper {
class DispatchQueue class DispatchQueue {
{
public: public:
virtual void async(dispatch_block_t block) = 0; virtual void async(dispatch_block_t block) = 0;
virtual ~DispatchQueue() {} virtual ~DispatchQueue() {}
}; };
class GCDQueue: public DispatchQueue class GCDQueue : public DispatchQueue {
{
public: public:
GCDQueue(dispatch_queue_t underlyingQueue) GCDQueue(dispatch_queue_t underlyingQueue)
: _underlyingQueue(underlyingQueue) {} : _underlyingQueue(underlyingQueue) {}
void async(dispatch_block_t block) override void async(dispatch_block_t block) override {
{
dispatch_async(_underlyingQueue, block); dispatch_async(_underlyingQueue, block);
} }
@@ -36,7 +33,7 @@ namespace facebook {
private: private:
dispatch_queue_t _underlyingQueue; dispatch_queue_t _underlyingQueue;
}; };
} } // namespace flipper
} } // namespace facebook
#endif #endif

View File

@@ -13,7 +13,10 @@
@property(strong, nonatomic) NSURLRequest* request; @property(strong, nonatomic) NSURLRequest* request;
@property(strong, nonatomic) NSString* body; @property(strong, nonatomic) NSString* body;
- (instancetype)initWithIdentifier:(int64_t)identifier timestamp:(uint64_t)timestamp request:(NSURLRequest*)request data:(NSData *)data; - (instancetype)initWithIdentifier:(int64_t)identifier
timestamp:(uint64_t)timestamp
request:(NSURLRequest*)request
data:(NSData*)data;
- (void)setBodyFromData:(NSData* _Nullable)data; - (void)setBodyFromData:(NSData* _Nullable)data;
@end @end

View File

@@ -13,8 +13,10 @@
@synthesize request = _request; @synthesize request = _request;
@synthesize body = _body; @synthesize body = _body;
- (instancetype)initWithIdentifier:(int64_t)identifier timestamp:(uint64_t)timestamp request:(NSURLRequest *)request data:(NSData *)data{ - (instancetype)initWithIdentifier:(int64_t)identifier
timestamp:(uint64_t)timestamp
request:(NSURLRequest*)request
data:(NSData*)data {
if (self = [super init]) { if (self = [super init]) {
_identifier = identifier; _identifier = identifier;
_timestamp = timestamp; _timestamp = timestamp;

View File

@@ -14,7 +14,10 @@
@property(strong, nonatomic) NSURLResponse* response; @property(strong, nonatomic) NSURLResponse* response;
@property(strong, nonatomic) NSString* body; @property(strong, nonatomic) NSString* body;
- (instancetype)initWithIndentifier:(int64_t)identifier timestamp:(uint64_t)timestamp response:(NSURLResponse *)response data:(NSData *)data; - (instancetype)initWithIndentifier:(int64_t)identifier
timestamp:(uint64_t)timestamp
response:(NSURLResponse*)response
data:(NSData*)data;
- (void)setBodyFromData:(NSData* _Nullable)data; - (void)setBodyFromData:(NSData* _Nullable)data;
@end @end

View File

@@ -13,12 +13,17 @@
@synthesize response = _response; @synthesize response = _response;
@synthesize body = _body; @synthesize body = _body;
- (instancetype)initWithIndentifier:(int64_t)identifier timestamp:(uint64_t)timestamp response:(NSURLResponse *)response data:(NSData *)data { - (instancetype)initWithIndentifier:(int64_t)identifier
timestamp:(uint64_t)timestamp
response:(NSURLResponse*)response
data:(NSData*)data {
if (self = [super init]) { if (self = [super init]) {
_identifier = identifier; _identifier = identifier;
_timestamp = timestamp; _timestamp = timestamp;
_response = response; _response = response;
_body = [SKResponseInfo shouldStripReponseBodyWithResponse:response] ? nil : [data base64EncodedStringWithOptions: 0]; _body = [SKResponseInfo shouldStripReponseBodyWithResponse:response]
? nil
: [data base64EncodedStringWithOptions:0];
} }
return self; return self;
} }
@@ -36,7 +41,9 @@
} }
- (void)setBodyFromData:(NSData* _Nullable)data { - (void)setBodyFromData:(NSData* _Nullable)data {
self.body = [SKResponseInfo shouldStripReponseBodyWithResponse:self.response] ? nil : [data base64EncodedStringWithOptions: 0]; self.body = [SKResponseInfo shouldStripReponseBodyWithResponse:self.response]
? nil
: [data base64EncodedStringWithOptions:0];
} }
@end @end

View File

@@ -8,11 +8,14 @@
#if FB_SONARKIT_ENABLED #if FB_SONARKIT_ENABLED
#pragma once #pragma once
#import <memory>
#import "FlipperKitNetworkPlugin.h" #import "FlipperKitNetworkPlugin.h"
#import "SKDispatchQueue.h" #import "SKDispatchQueue.h"
#import <memory>
@interface FlipperKitNetworkPlugin (CPPInitialization) @interface FlipperKitNetworkPlugin (CPPInitialization)
- (instancetype)initWithNetworkAdapter:(id<SKNetworkAdapterDelegate>)adapter dispatchQueue:(std::shared_ptr<facebook::flipper::DispatchQueue>)queue; - (instancetype)initWithNetworkAdapter:(id<SKNetworkAdapterDelegate>)adapter
dispatchQueue:
(std::shared_ptr<facebook::flipper::DispatchQueue>)
queue;
@end @end
#endif #endif

View File

@@ -21,10 +21,13 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
FOUNDATION_EXTERN NSString *const kFLEXNetworkObserverEnabledStateChangedNotification; FOUNDATION_EXTERN NSString* const
kFLEXNetworkObserverEnabledStateChangedNotification;
/// This class swizzles NSURLConnection and NSURLSession delegate methods to observe events in the URL loading system. /// This class swizzles NSURLConnection and NSURLSession delegate methods to
/// High level network events are sent to the default FLEXNetworkRecorder instance which maintains the request history and caches response bodies. /// observe events in the URL loading system. High level network events are sent
/// to the default FLEXNetworkRecorder instance which maintains the request
/// history and caches response bodies.
@interface FLEXNetworkObserver : NSObject @interface FLEXNetworkObserver : NSObject
+ (void)start; + (void)start;

View File

@@ -19,51 +19,61 @@ extern NSString *const kFLEXNetworkRecorderTransactionsClearedNotification;
@interface FLEXNetworkRecorder : NSObject @interface FLEXNetworkRecorder : NSObject
/// In general, it only makes sense to have one recorder for the entire application. /// In general, it only makes sense to have one recorder for the entire
/// application.
+ (instancetype)defaultRecorder; + (instancetype)defaultRecorder;
@property(nonatomic, weak) id<SKNetworkReporterDelegate> delegate; @property(nonatomic, weak) id<SKNetworkReporterDelegate> delegate;
/// Defaults to 25 MB if never set. Values set here are presisted across launches of the app. /// Defaults to 25 MB if never set. Values set here are presisted across
/// launches of the app.
@property(nonatomic, assign) NSUInteger responseCacheByteLimit; @property(nonatomic, assign) NSUInteger responseCacheByteLimit;
/// If NO, the recorder not cache will not cache response for content types with an "image", "video", or "audio" prefix. /// If NO, the recorder not cache will not cache response for content types with
/// an "image", "video", or "audio" prefix.
@property(nonatomic, assign) BOOL shouldCacheMediaResponses; @property(nonatomic, assign) BOOL shouldCacheMediaResponses;
@property(nonatomic, copy) NSArray<NSString*>* hostBlacklist; @property(nonatomic, copy) NSArray<NSString*>* hostBlacklist;
// Accessing recorded network activity // Accessing recorded network activity
/// Array of FLEXNetworkTransaction objects ordered by start time with the newest first. /// Array of FLEXNetworkTransaction objects ordered by start time with the
/// newest first.
- (NSArray<FLEXNetworkTransaction*>*)networkTransactions; - (NSArray<FLEXNetworkTransaction*>*)networkTransactions;
/// The full response data IFF it hasn't been purged due to memory pressure. /// The full response data IFF it hasn't been purged due to memory pressure.
- (NSData *)cachedResponseBodyForTransaction:(FLEXNetworkTransaction *)transaction; - (NSData*)cachedResponseBodyForTransaction:
(FLEXNetworkTransaction*)transaction;
/// Dumps all network transactions and cached response bodies. /// Dumps all network transactions and cached response bodies.
- (void)clearRecordedActivity; - (void)clearRecordedActivity;
// Recording network activity // Recording network activity
/// Call when app is about to send HTTP request. /// Call when app is about to send HTTP request.
- (void)recordRequestWillBeSentWithRequestID:(NSString *)requestID request:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse; - (void)recordRequestWillBeSentWithRequestID:(NSString*)requestID
request:(NSURLRequest*)request
redirectResponse:(NSURLResponse*)redirectResponse;
/// Call when HTTP response is available. /// Call when HTTP response is available.
- (void)recordResponseReceivedWithRequestID:(NSString *)requestID response:(NSURLResponse *)response; - (void)recordResponseReceivedWithRequestID:(NSString*)requestID
response:(NSURLResponse*)response;
/// Call when data chunk is received over the network. /// Call when data chunk is received over the network.
- (void)recordDataReceivedWithRequestID:(NSString *)requestID dataLength:(int64_t)dataLength; - (void)recordDataReceivedWithRequestID:(NSString*)requestID
dataLength:(int64_t)dataLength;
/// Call when HTTP request has finished loading. /// Call when HTTP request has finished loading.
- (void)recordLoadingFinishedWithRequestID:(NSString *)requestID responseBody:(NSData *)responseBody; - (void)recordLoadingFinishedWithRequestID:(NSString*)requestID
responseBody:(NSData*)responseBody;
/// Call when HTTP request has failed to load. /// Call when HTTP request has failed to load.
- (void)recordLoadingFailedWithRequestID:(NSString *)requestID error:(NSError *)error; - (void)recordLoadingFailedWithRequestID:(NSString*)requestID
error:(NSError*)error;
/// Call to set the request mechanism anytime after recordRequestWillBeSent... has been called. /// Call to set the request mechanism anytime after recordRequestWillBeSent...
/// This string can be set to anything useful about the API used to make the request. /// has been called. This string can be set to anything useful about the API
/// used to make the request.
- (void)recordMechanism:(NSString*)mechanism forRequestID:(NSString*)requestID; - (void)recordMechanism:(NSString*)mechanism forRequestID:(NSString*)requestID;
@end @end

View File

@@ -10,48 +10,59 @@
#import "FLEXNetworkTransaction.h" #import "FLEXNetworkTransaction.h"
#import "FLEXUtility.h" #import "FLEXUtility.h"
NSString *const kFLEXNetworkRecorderNewTransactionNotification = @"kFLEXNetworkRecorderNewTransactionNotification"; NSString* const kFLEXNetworkRecorderNewTransactionNotification =
NSString *const kFLEXNetworkRecorderTransactionUpdatedNotification = @"kFLEXNetworkRecorderTransactionUpdatedNotification"; @"kFLEXNetworkRecorderNewTransactionNotification";
NSString* const kFLEXNetworkRecorderTransactionUpdatedNotification =
@"kFLEXNetworkRecorderTransactionUpdatedNotification";
NSString* const kFLEXNetworkRecorderUserInfoTransactionKey = @"transaction"; NSString* const kFLEXNetworkRecorderUserInfoTransactionKey = @"transaction";
NSString *const kFLEXNetworkRecorderTransactionsClearedNotification = @"kFLEXNetworkRecorderTransactionsClearedNotification"; NSString* const kFLEXNetworkRecorderTransactionsClearedNotification =
@"kFLEXNetworkRecorderTransactionsClearedNotification";
NSString *const kFLEXNetworkRecorderResponseCacheLimitDefaultsKey = @"com.flex.responseCacheLimit"; NSString* const kFLEXNetworkRecorderResponseCacheLimitDefaultsKey =
@"com.flex.responseCacheLimit";
@interface FLEXNetworkRecorder () @interface FLEXNetworkRecorder ()
@property(nonatomic, strong) NSCache* responseCache; @property(nonatomic, strong) NSCache* responseCache;
@property (nonatomic, strong) NSMutableArray<FLEXNetworkTransaction *> *orderedTransactions; @property(nonatomic, strong)
@property (nonatomic, strong) NSMutableDictionary<NSString *, FLEXNetworkTransaction *> *networkTransactionsForRequestIdentifiers; NSMutableArray<FLEXNetworkTransaction*>* orderedTransactions;
@property(nonatomic, strong)
NSMutableDictionary<NSString*, FLEXNetworkTransaction*>*
networkTransactionsForRequestIdentifiers;
@property(nonatomic, strong) dispatch_queue_t queue; @property(nonatomic, strong) dispatch_queue_t queue;
@property (nonatomic, strong) NSMutableDictionary<NSString *, NSNumber *> *identifierDict; @property(nonatomic, strong)
NSMutableDictionary<NSString*, NSNumber*>* identifierDict;
@end @end
@implementation FLEXNetworkRecorder @implementation FLEXNetworkRecorder
- (instancetype)init - (instancetype)init {
{
self = [super init]; self = [super init];
if (self) { if (self) {
_responseCache = [NSCache new]; _responseCache = [NSCache new];
NSUInteger responseCacheLimit = [[[NSUserDefaults standardUserDefaults] objectForKey:kFLEXNetworkRecorderResponseCacheLimitDefaultsKey] unsignedIntegerValue]; NSUInteger responseCacheLimit = [[[NSUserDefaults standardUserDefaults]
objectForKey:kFLEXNetworkRecorderResponseCacheLimitDefaultsKey]
unsignedIntegerValue];
if (responseCacheLimit) { if (responseCacheLimit) {
[_responseCache setTotalCostLimit:responseCacheLimit]; [_responseCache setTotalCostLimit:responseCacheLimit];
} else { } else {
// Default to 25 MB max. The cache will purge earlier if there is memory pressure. // Default to 25 MB max. The cache will purge earlier if there is memory
// pressure.
[_responseCache setTotalCostLimit:25 * 1024 * 1024]; [_responseCache setTotalCostLimit:25 * 1024 * 1024];
} }
_orderedTransactions = [NSMutableArray array]; _orderedTransactions = [NSMutableArray array];
_networkTransactionsForRequestIdentifiers = [NSMutableDictionary dictionary]; _networkTransactionsForRequestIdentifiers =
[NSMutableDictionary dictionary];
// Serial queue used because we use mutable objects that are not thread safe // Serial queue used because we use mutable objects that are not thread safe
_queue = dispatch_queue_create("com.flex.FLEXNetworkRecorder", DISPATCH_QUEUE_SERIAL); _queue = dispatch_queue_create(
"com.flex.FLEXNetworkRecorder", DISPATCH_QUEUE_SERIAL);
_identifierDict = [NSMutableDictionary dictionary]; _identifierDict = [NSMutableDictionary dictionary];
} }
return self; return self;
} }
+ (instancetype)defaultRecorder + (instancetype)defaultRecorder {
{
static FLEXNetworkRecorder* defaultRecorder = nil; static FLEXNetworkRecorder* defaultRecorder = nil;
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{
@@ -66,19 +77,18 @@ NSString *const kFLEXNetworkRecorderResponseCacheLimitDefaultsKey = @"com.flex.r
_delegate = delegate; _delegate = delegate;
} }
- (NSUInteger)responseCacheByteLimit - (NSUInteger)responseCacheByteLimit {
{
return [self.responseCache totalCostLimit]; return [self.responseCache totalCostLimit];
} }
- (void)setResponseCacheByteLimit:(NSUInteger)responseCacheByteLimit - (void)setResponseCacheByteLimit:(NSUInteger)responseCacheByteLimit {
{
[self.responseCache setTotalCostLimit:responseCacheByteLimit]; [self.responseCache setTotalCostLimit:responseCacheByteLimit];
[[NSUserDefaults standardUserDefaults] setObject:@(responseCacheByteLimit) forKey:kFLEXNetworkRecorderResponseCacheLimitDefaultsKey]; [[NSUserDefaults standardUserDefaults]
setObject:@(responseCacheByteLimit)
forKey:kFLEXNetworkRecorderResponseCacheLimitDefaultsKey];
} }
- (NSArray<FLEXNetworkTransaction *> *)networkTransactions - (NSArray<FLEXNetworkTransaction*>*)networkTransactions {
{
__block NSArray<FLEXNetworkTransaction*>* transactions = nil; __block NSArray<FLEXNetworkTransaction*>* transactions = nil;
dispatch_sync(self.queue, ^{ dispatch_sync(self.queue, ^{
transactions = [self.orderedTransactions copy]; transactions = [self.orderedTransactions copy];
@@ -86,13 +96,12 @@ NSString *const kFLEXNetworkRecorderResponseCacheLimitDefaultsKey = @"com.flex.r
return transactions; return transactions;
} }
- (NSData *)cachedResponseBodyForTransaction:(FLEXNetworkTransaction *)transaction - (NSData*)cachedResponseBodyForTransaction:
{ (FLEXNetworkTransaction*)transaction {
return [self.responseCache objectForKey:transaction.requestID]; return [self.responseCache objectForKey:transaction.requestID];
} }
- (void)clearRecordedActivity - (void)clearRecordedActivity {
{
dispatch_async(self.queue, ^{ dispatch_async(self.queue, ^{
[self.responseCache removeAllObjects]; [self.responseCache removeAllObjects];
[self.orderedTransactions removeAllObjects]; [self.orderedTransactions removeAllObjects];
@@ -102,20 +111,26 @@ NSString *const kFLEXNetworkRecorderResponseCacheLimitDefaultsKey = @"com.flex.r
#pragma mark - Network Events #pragma mark - Network Events
- (void)recordRequestWillBeSentWithRequestID:(NSString *)requestID request:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse - (void)recordRequestWillBeSentWithRequestID:(NSString*)requestID
{ request:(NSURLRequest*)request
redirectResponse:(NSURLResponse*)redirectResponse {
if (![self.identifierDict objectForKey:requestID]) { if (![self.identifierDict objectForKey:requestID]) {
self.identifierDict[requestID] = [NSNumber random]; self.identifierDict[requestID] = [NSNumber random];
} }
NSDate* startDate = [NSDate date]; NSDate* startDate = [NSDate date];
if (redirectResponse) { if (redirectResponse) {
[self recordResponseReceivedWithRequestID:requestID response:redirectResponse]; [self recordResponseReceivedWithRequestID:requestID
response:redirectResponse];
[self recordLoadingFinishedWithRequestID:requestID responseBody:nil]; [self recordLoadingFinishedWithRequestID:requestID responseBody:nil];
} }
dispatch_async(self.queue, ^{ dispatch_async(self.queue, ^{
SKRequestInfo *info = [[SKRequestInfo alloc] initWithIdentifier:self.identifierDict[requestID].longLongValue timestamp:[NSDate timestamp] request:request data:request.HTTPBody]; SKRequestInfo* info = [[SKRequestInfo alloc]
initWithIdentifier:self.identifierDict[requestID].longLongValue
timestamp:[NSDate timestamp]
request:request
data:request.HTTPBody];
[self.delegate didObserveRequest:info]; [self.delegate didObserveRequest:info];
FLEXNetworkTransaction* transaction = [FLEXNetworkTransaction new]; FLEXNetworkTransaction* transaction = [FLEXNetworkTransaction new];
@@ -124,32 +139,36 @@ NSString *const kFLEXNetworkRecorderResponseCacheLimitDefaultsKey = @"com.flex.r
transaction.startTime = startDate; transaction.startTime = startDate;
[self.orderedTransactions insertObject:transaction atIndex:0]; [self.orderedTransactions insertObject:transaction atIndex:0];
[self.networkTransactionsForRequestIdentifiers setObject:transaction forKey:requestID]; [self.networkTransactionsForRequestIdentifiers setObject:transaction
forKey:requestID];
transaction.transactionState = FLEXNetworkTransactionStateAwaitingResponse; transaction.transactionState = FLEXNetworkTransactionStateAwaitingResponse;
}); });
} }
/// Call when HTTP response is available. /// Call when HTTP response is available.
- (void)recordResponseReceivedWithRequestID:(NSString *)requestID response:(NSURLResponse *)response - (void)recordResponseReceivedWithRequestID:(NSString*)requestID
{ response:(NSURLResponse*)response {
NSDate* responseDate = [NSDate date]; NSDate* responseDate = [NSDate date];
dispatch_async(self.queue, ^{ dispatch_async(self.queue, ^{
FLEXNetworkTransaction *transaction = self.networkTransactionsForRequestIdentifiers[requestID]; FLEXNetworkTransaction* transaction =
self.networkTransactionsForRequestIdentifiers[requestID];
if (!transaction) { if (!transaction) {
return; return;
} }
transaction.response = response; transaction.response = response;
transaction.transactionState = FLEXNetworkTransactionStateReceivingData; transaction.transactionState = FLEXNetworkTransactionStateReceivingData;
transaction.latency = -[transaction.startTime timeIntervalSinceDate:responseDate]; transaction.latency =
-[transaction.startTime timeIntervalSinceDate:responseDate];
}); });
} }
/// Call when data chunk is received over the network. /// Call when data chunk is received over the network.
- (void)recordDataReceivedWithRequestID:(NSString *)requestID dataLength:(int64_t)dataLength - (void)recordDataReceivedWithRequestID:(NSString*)requestID
{ dataLength:(int64_t)dataLength {
dispatch_async(self.queue, ^{ dispatch_async(self.queue, ^{
FLEXNetworkTransaction *transaction = self.networkTransactionsForRequestIdentifiers[requestID]; FLEXNetworkTransaction* transaction =
self.networkTransactionsForRequestIdentifiers[requestID];
if (!transaction) { if (!transaction) {
return; return;
} }
@@ -158,44 +177,58 @@ NSString *const kFLEXNetworkRecorderResponseCacheLimitDefaultsKey = @"com.flex.r
} }
/// Call when HTTP request has finished loading. /// Call when HTTP request has finished loading.
- (void)recordLoadingFinishedWithRequestID:(NSString *)requestID responseBody:(NSData *)responseBody - (void)recordLoadingFinishedWithRequestID:(NSString*)requestID
{ responseBody:(NSData*)responseBody {
NSDate* finishedDate = [NSDate date]; NSDate* finishedDate = [NSDate date];
dispatch_async(self.queue, ^{ dispatch_async(self.queue, ^{
FLEXNetworkTransaction* transaction =
FLEXNetworkTransaction *transaction = self.networkTransactionsForRequestIdentifiers[requestID]; self.networkTransactionsForRequestIdentifiers[requestID];
if (!transaction) { if (!transaction) {
return; return;
} }
transaction.transactionState = FLEXNetworkTransactionStateFinished; transaction.transactionState = FLEXNetworkTransactionStateFinished;
transaction.duration = -[transaction.startTime timeIntervalSinceDate:finishedDate]; transaction.duration =
SKResponseInfo *responseInfo = [[SKResponseInfo alloc] initWithIndentifier:self.identifierDict[requestID].longLongValue timestamp:[NSDate timestamp] response:transaction.response data:responseBody]; -[transaction.startTime timeIntervalSinceDate:finishedDate];
SKResponseInfo* responseInfo = [[SKResponseInfo alloc]
initWithIndentifier:self.identifierDict[requestID].longLongValue
timestamp:[NSDate timestamp]
response:transaction.response
data:responseBody];
self.identifierDict[requestID] = nil; // Clear the entry self.identifierDict[requestID] = nil; // Clear the entry
[self.delegate didObserveResponse:responseInfo]; [self.delegate didObserveResponse:responseInfo];
BOOL shouldCache = [responseBody length] > 0; BOOL shouldCache = [responseBody length] > 0;
if (!self.shouldCacheMediaResponses) { if (!self.shouldCacheMediaResponses) {
NSArray<NSString *> *ignoredMIMETypePrefixes = @[ @"audio", @"image", @"video" ]; NSArray<NSString*>* ignoredMIMETypePrefixes =
@[ @"audio", @"image", @"video" ];
for (NSString* ignoredPrefix in ignoredMIMETypePrefixes) { for (NSString* ignoredPrefix in ignoredMIMETypePrefixes) {
shouldCache = shouldCache && ![transaction.response.MIMEType hasPrefix:ignoredPrefix]; shouldCache = shouldCache &&
![transaction.response.MIMEType hasPrefix:ignoredPrefix];
} }
} }
if (shouldCache) { if (shouldCache) {
[self.responseCache setObject:responseBody forKey:requestID cost:[responseBody length]]; [self.responseCache setObject:responseBody
forKey:requestID
cost:[responseBody length]];
} }
}); });
} }
- (void)recordLoadingFailedWithRequestID:(NSString *)requestID error:(NSError *)error - (void)recordLoadingFailedWithRequestID:(NSString*)requestID
{ error:(NSError*)error {
dispatch_async(self.queue, ^{ dispatch_async(self.queue, ^{
FLEXNetworkTransaction *transaction = self.networkTransactionsForRequestIdentifiers[requestID]; FLEXNetworkTransaction* transaction =
self.networkTransactionsForRequestIdentifiers[requestID];
if (!transaction) { if (!transaction) {
return; return;
} }
SKResponseInfo *responseInfo = [[SKResponseInfo alloc] initWithIndentifier:self.identifierDict[requestID].longLongValue timestamp:[NSDate timestamp] response:transaction.response data: nil]; SKResponseInfo* responseInfo = [[SKResponseInfo alloc]
initWithIndentifier:self.identifierDict[requestID].longLongValue
timestamp:[NSDate timestamp]
response:transaction.response
data:nil];
self.identifierDict[requestID] = nil; // Clear the entry self.identifierDict[requestID] = nil; // Clear the entry
[self.delegate didObserveResponse:responseInfo]; [self.delegate didObserveResponse:responseInfo];
transaction.transactionState = FLEXNetworkTransactionStateFailed; transaction.transactionState = FLEXNetworkTransactionStateFailed;
@@ -204,10 +237,10 @@ NSString *const kFLEXNetworkRecorderResponseCacheLimitDefaultsKey = @"com.flex.r
}); });
} }
- (void)recordMechanism:(NSString *)mechanism forRequestID:(NSString *)requestID - (void)recordMechanism:(NSString*)mechanism forRequestID:(NSString*)requestID {
{
dispatch_async(self.queue, ^{ dispatch_async(self.queue, ^{
FLEXNetworkTransaction *transaction = self.networkTransactionsForRequestIdentifiers[requestID]; FLEXNetworkTransaction* transaction =
self.networkTransactionsForRequestIdentifiers[requestID];
if (!transaction) { if (!transaction) {
return; return;
} }

View File

@@ -33,12 +33,14 @@ typedef NS_ENUM(NSInteger, FLEXNetworkTransactionState) {
@property(nonatomic, assign) int64_t receivedDataLength; @property(nonatomic, assign) int64_t receivedDataLength;
/// Only applicable for image downloads. A small thumbnail to preview the full response. /// Only applicable for image downloads. A small thumbnail to preview the full
/// response.
@property(nonatomic, strong) UIImage* responseThumbnail; @property(nonatomic, strong) UIImage* responseThumbnail;
/// Populated lazily. Handles both normal HTTPBody data and HTTPBodyStreams. /// Populated lazily. Handles both normal HTTPBody data and HTTPBodyStreams.
@property(nonatomic, strong, readonly) NSData* cachedRequestBody; @property(nonatomic, strong, readonly) NSData* cachedRequestBody;
+ (NSString *)readableStringFromTransactionState:(FLEXNetworkTransactionState)state; + (NSString*)readableStringFromTransactionState:
(FLEXNetworkTransactionState)state;
@end @end

View File

@@ -15,14 +15,18 @@
@implementation FLEXNetworkTransaction @implementation FLEXNetworkTransaction
- (NSString *)description - (NSString*)description {
{
NSString* description = [super description]; NSString* description = [super description];
description = [description stringByAppendingFormat:@" id = %@;", self.requestID]; description =
description = [description stringByAppendingFormat:@" url = %@;", self.request.URL]; [description stringByAppendingFormat:@" id = %@;", self.requestID];
description = [description stringByAppendingFormat:@" duration = %f;", self.duration]; description =
description = [description stringByAppendingFormat:@" receivedDataLength = %lld", self.receivedDataLength]; [description stringByAppendingFormat:@" url = %@;", self.request.URL];
description =
[description stringByAppendingFormat:@" duration = %f;", self.duration];
description =
[description stringByAppendingFormat:@" receivedDataLength = %lld",
self.receivedDataLength];
return description; return description;
} }
@@ -31,7 +35,8 @@
if (!_cachedRequestBody) { if (!_cachedRequestBody) {
if (self.request.HTTPBody != nil) { if (self.request.HTTPBody != nil) {
_cachedRequestBody = self.request.HTTPBody; _cachedRequestBody = self.request.HTTPBody;
} else if ([self.request.HTTPBodyStream conformsToProtocol:@protocol(NSCopying)]) { } else if ([self.request.HTTPBodyStream
conformsToProtocol:@protocol(NSCopying)]) {
NSInputStream* bodyStream = [self.request.HTTPBodyStream copy]; NSInputStream* bodyStream = [self.request.HTTPBodyStream copy];
const NSUInteger bufferSize = 1024; const NSUInteger bufferSize = 1024;
uint8_t buffer[bufferSize]; uint8_t buffer[bufferSize];
@@ -49,8 +54,8 @@
return _cachedRequestBody; return _cachedRequestBody;
} }
+ (NSString *)readableStringFromTransactionState:(FLEXNetworkTransactionState)state + (NSString*)readableStringFromTransactionState:
{ (FLEXNetworkTransactionState)state {
NSString* readableString = nil; NSString* readableString = nil;
switch (state) { switch (state) {
case FLEXNetworkTransactionStateUnstarted: case FLEXNetworkTransactionStateUnstarted:

View File

@@ -12,9 +12,11 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#define FLEXFloor(x) (floor([[UIScreen mainScreen] scale] * (x)) / [[UIScreen mainScreen] scale]) #define FLEXFloor(x) \
(floor([[UIScreen mainScreen] scale] * (x)) / [[UIScreen mainScreen] scale])
#define FLEX_AT_LEAST_IOS11_SDK defined(__IPHONE_11_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0) #define FLEX_AT_LEAST_IOS11_SDK \
defined(__IPHONE_11_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0)
@interface NSNumber (SonarUtility) @interface NSNumber (SonarUtility)
@@ -32,8 +34,18 @@
// Swizzling utilities // Swizzling utilities
+ (SEL)swizzledSelectorForSelector:(SEL)selector; + (SEL)swizzledSelectorForSelector:(SEL)selector;
+ (BOOL)instanceRespondsButDoesNotImplementSelector:(SEL)selector class:(Class)cls; + (BOOL)instanceRespondsButDoesNotImplementSelector:(SEL)selector
+ (void)replaceImplementationOfKnownSelector:(SEL)originalSelector onClass:(Class)className withBlock:(id)block swizzledSelector:(SEL)swizzledSelector; class:(Class)cls;
+ (void)replaceImplementationOfSelector:(SEL)selector withSelector:(SEL)swizzledSelector forClass:(Class)cls withMethodDescription:(struct objc_method_description)methodDescription implementationBlock:(id)implementationBlock undefinedBlock:(id)undefinedBlock; + (void)replaceImplementationOfKnownSelector:(SEL)originalSelector
onClass:(Class)className
withBlock:(id)block
swizzledSelector:(SEL)swizzledSelector;
+ (void)replaceImplementationOfSelector:(SEL)selector
withSelector:(SEL)swizzledSelector
forClass:(Class)cls
withMethodDescription:
(struct objc_method_description)methodDescription
implementationBlock:(id)implementationBlock
undefinedBlock:(id)undefinedBlock;
@end @end

View File

@@ -7,23 +7,25 @@
#import "FLEXUtility.h" #import "FLEXUtility.h"
#import <objc/runtime.h>
#include <assert.h> #include <assert.h>
#import <zlib.h>
#include <mach/mach.h> #include <mach/mach.h>
#include <mach/mach_time.h> #include <mach/mach_time.h>
#import <objc/runtime.h>
#import <zlib.h>
#import <ImageIO/ImageIO.h> #import <ImageIO/ImageIO.h>
@implementation FLEXUtility @implementation FLEXUtility
+ (SEL)swizzledSelectorForSelector:(SEL)selector + (SEL)swizzledSelectorForSelector:(SEL)selector {
{ return NSSelectorFromString(
return NSSelectorFromString([NSString stringWithFormat:@"_flex_swizzle_%x_%@", arc4random(), NSStringFromSelector(selector)]); [NSString stringWithFormat:@"_flex_swizzle_%x_%@",
arc4random(),
NSStringFromSelector(selector)]);
} }
+ (BOOL)instanceRespondsButDoesNotImplementSelector:(SEL)selector class:(Class)cls + (BOOL)instanceRespondsButDoesNotImplementSelector:(SEL)selector
{ class:(Class)cls {
if ([cls instancesRespondToSelector:selector]) { if ([cls instancesRespondToSelector:selector]) {
unsigned int numMethods = 0; unsigned int numMethods = 0;
Method* methods = class_copyMethodList(cls, &numMethods); Method* methods = class_copyMethodList(cls, &numMethods);
@@ -47,32 +49,46 @@
return NO; return NO;
} }
+ (void)replaceImplementationOfKnownSelector:(SEL)originalSelector onClass:(Class)className withBlock:(id)block swizzledSelector:(SEL)swizzledSelector + (void)replaceImplementationOfKnownSelector:(SEL)originalSelector
{ onClass:(Class)className
// This method is only intended for swizzling methods that are know to exist on the class. withBlock:(id)block
// Bail if that isn't the case. swizzledSelector:(SEL)swizzledSelector {
// This method is only intended for swizzling methods that are know to exist
// on the class. Bail if that isn't the case.
Method originalMethod = class_getInstanceMethod(className, originalSelector); Method originalMethod = class_getInstanceMethod(className, originalSelector);
if (!originalMethod) { if (!originalMethod) {
return; return;
} }
IMP implementation = imp_implementationWithBlock(block); IMP implementation = imp_implementationWithBlock(block);
class_addMethod(className, swizzledSelector, implementation, method_getTypeEncoding(originalMethod)); class_addMethod(
className,
swizzledSelector,
implementation,
method_getTypeEncoding(originalMethod));
Method newMethod = class_getInstanceMethod(className, swizzledSelector); Method newMethod = class_getInstanceMethod(className, swizzledSelector);
method_exchangeImplementations(originalMethod, newMethod); method_exchangeImplementations(originalMethod, newMethod);
} }
+ (void)replaceImplementationOfSelector:(SEL)selector withSelector:(SEL)swizzledSelector forClass:(Class)cls withMethodDescription:(struct objc_method_description)methodDescription implementationBlock:(id)implementationBlock undefinedBlock:(id)undefinedBlock + (void)replaceImplementationOfSelector:(SEL)selector
{ withSelector:(SEL)swizzledSelector
forClass:(Class)cls
withMethodDescription:
(struct objc_method_description)methodDescription
implementationBlock:(id)implementationBlock
undefinedBlock:(id)undefinedBlock {
if ([self instanceRespondsButDoesNotImplementSelector:selector class:cls]) { if ([self instanceRespondsButDoesNotImplementSelector:selector class:cls]) {
return; return;
} }
IMP implementation = imp_implementationWithBlock((id)([cls instancesRespondToSelector:selector] ? implementationBlock : undefinedBlock)); IMP implementation = imp_implementationWithBlock((id)(
[cls instancesRespondToSelector:selector] ? implementationBlock
: undefinedBlock));
Method oldMethod = class_getInstanceMethod(cls, selector); Method oldMethod = class_getInstanceMethod(cls, selector);
if (oldMethod) { if (oldMethod) {
class_addMethod(cls, swizzledSelector, implementation, methodDescription.types); class_addMethod(
cls, swizzledSelector, implementation, methodDescription.types);
Method newMethod = class_getInstanceMethod(cls, swizzledSelector); Method newMethod = class_getInstanceMethod(cls, swizzledSelector);
@@ -96,8 +112,7 @@
@implementation NSDate (SonarUtility) @implementation NSDate (SonarUtility)
+ (uint64_t)getTimeNanoseconds + (uint64_t)getTimeNanoseconds {
{
static struct mach_timebase_info tb_info = {0}; static struct mach_timebase_info tb_info = {0};
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{

View File

@@ -7,8 +7,8 @@
#if FB_SONARKIT_ENABLED #if FB_SONARKIT_ENABLED
#import <Foundation/Foundation.h>
#import <FlipperKitNetworkPlugin/SKNetworkReporter.h> #import <FlipperKitNetworkPlugin/SKNetworkReporter.h>
#import <Foundation/Foundation.h>
@interface SKIOSNetworkAdapter : NSObject<SKNetworkAdapterDelegate> @interface SKIOSNetworkAdapter : NSObject<SKNetworkAdapterDelegate>
- (instancetype)init NS_DESIGNATED_INITIALIZER; - (instancetype)init NS_DESIGNATED_INITIALIZER;

View File

@@ -9,8 +9,7 @@
#import "SKHighlightOverlay.h" #import "SKHighlightOverlay.h"
@implementation SKHighlightOverlay @implementation SKHighlightOverlay {
{
CALayer* _overlayLayer; CALayer* _overlayLayer;
} }
@@ -46,7 +45,10 @@
} }
+ (UIColor*)overlayColor { + (UIColor*)overlayColor {
return [UIColor colorWithRed:136.0 / 255.0 green:117.0 / 255.0 blue:197.0 / 255.0 alpha:0.6]; return [UIColor colorWithRed:136.0 / 255.0
green:117.0 / 255.0
blue:197.0 / 255.0
alpha:0.6];
} }
@end @end

View File

@@ -13,8 +13,7 @@
#import "Plugins.h" #import "Plugins.h"
void FlipperKitReactPluginInit(FlipperClient *client) void FlipperKitReactPluginInit(FlipperClient* client) {
{
[client addPlugin:[FlipperKitReactPlugin new]]; [client addPlugin:[FlipperKitReactPlugin new]];
} }

View File

@@ -5,8 +5,8 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
#import <Foundation/Foundation.h>
#import <FlipperKit/FlipperPlugin.h> #import <FlipperKit/FlipperPlugin.h>
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN

View File

@@ -27,13 +27,20 @@ static NSString *const kAppSuiteUserDefaultsName = @"App Suite UserDefaults";
if (self = [super init]) { if (self = [super init]) {
_standardUserDefaults = [NSUserDefaults standardUserDefaults]; _standardUserDefaults = [NSUserDefaults standardUserDefaults];
__weak typeof(self) weakSelf = self; __weak typeof(self) weakSelf = self;
[FKUserDefaultsSwizzleUtility swizzleSelector:@selector(setObject:forKey:) class:[NSUserDefaults class] block:^(NSInvocation * _Nonnull invocation) { [FKUserDefaultsSwizzleUtility
swizzleSelector:@selector(setObject:forKey:)
class:[NSUserDefaults class]
block:^(NSInvocation* _Nonnull invocation) {
__unsafe_unretained id firstArg = nil; __unsafe_unretained id firstArg = nil;
__unsafe_unretained id secondArg = nil; __unsafe_unretained id secondArg = nil;
[invocation getArgument:&firstArg atIndex:2]; [invocation getArgument:&firstArg atIndex:2];
[invocation getArgument:&secondArg atIndex:3]; [invocation getArgument:&secondArg atIndex:3];
[invocation invoke]; [invocation invoke];
[weakSelf userDefaults:([invocation.target isKindOfClass:[NSUserDefaults class]] ? invocation.target : nil) [weakSelf userDefaults:([invocation.target
isKindOfClass:[NSUserDefaults
class]]
? invocation.target
: nil)
changedWithValue:firstArg changedWithValue:firstArg
key:secondArg]; key:secondArg];
}]; }];
@@ -45,7 +52,8 @@ static NSString *const kAppSuiteUserDefaultsName = @"App Suite UserDefaults";
if (self = [self init]) { if (self = [self init]) {
_suiteName = suiteName; _suiteName = suiteName;
if (_suiteName) { if (_suiteName) {
_appSuiteUserDefaults = [[NSUserDefaults alloc] initWithSuiteName:_suiteName]; _appSuiteUserDefaults =
[[NSUserDefaults alloc] initWithSuiteName:_suiteName];
} }
} }
return self; return self;
@@ -53,19 +61,25 @@ static NSString *const kAppSuiteUserDefaultsName = @"App Suite UserDefaults";
- (void)didConnect:(id<FlipperConnection>)connection { - (void)didConnect:(id<FlipperConnection>)connection {
self.flipperConnection = connection; self.flipperConnection = connection;
[connection receive:@"getAllSharedPreferences" withBlock:^(NSDictionary *params, id<FlipperResponder> responder) { [connection receive:@"getAllSharedPreferences"
withBlock:^(NSDictionary* params, id<FlipperResponder> responder) {
NSMutableDictionary* userDefaults = [NSMutableDictionary new]; NSMutableDictionary* userDefaults = [NSMutableDictionary new];
userDefaults[kStandardUserDefaultsName] = [self.standardUserDefaults dictionaryRepresentation]; userDefaults[kStandardUserDefaultsName] =
[self.standardUserDefaults dictionaryRepresentation];
if (self.appSuiteUserDefaults) { if (self.appSuiteUserDefaults) {
userDefaults[kAppSuiteUserDefaultsName] = [self.appSuiteUserDefaults dictionaryRepresentation]; userDefaults[kAppSuiteUserDefaultsName] =
[self.appSuiteUserDefaults dictionaryRepresentation];
} }
[responder success:userDefaults]; [responder success:userDefaults];
}]; }];
[connection receive:@"setSharedPreference" withBlock:^(NSDictionary *params , id<FlipperResponder> responder) { [connection receive:@"setSharedPreference"
NSUserDefaults *sharedPreferences = [self sharedPreferencesForParams:params]; withBlock:^(NSDictionary* params, id<FlipperResponder> responder) {
NSUserDefaults* sharedPreferences =
[self sharedPreferencesForParams:params];
NSString* preferenceName = params[@"preferenceName"]; NSString* preferenceName = params[@"preferenceName"];
[sharedPreferences setObject:params[@"preferenceValue"] forKey:preferenceName]; [sharedPreferences setObject:params[@"preferenceValue"]
forKey:preferenceName];
[responder success:[sharedPreferences dictionaryRepresentation]]; [responder success:[sharedPreferences dictionaryRepresentation]];
}]; }];
} }
@@ -87,17 +101,19 @@ static NSString *const kAppSuiteUserDefaultsName = @"App Suite UserDefaults";
} }
NSString* sharedPreferencesName = params[sharedPreferencesNameKey]; NSString* sharedPreferencesName = params[sharedPreferencesNameKey];
return ([sharedPreferencesName isEqualToString:kAppSuiteUserDefaultsName] return (
[sharedPreferencesName isEqualToString:kAppSuiteUserDefaultsName]
? _appSuiteUserDefaults ? _appSuiteUserDefaults
: _standardUserDefaults); : _standardUserDefaults);
} }
- (void)userDefaults:(NSUserDefaults *)userDefaults changedWithValue:(id)value key:(NSString *)key { - (void)userDefaults:(NSUserDefaults*)userDefaults
changedWithValue:(id)value
key:(NSString*)key {
NSTimeInterval interval = [[NSDate date] timeIntervalSince1970] * 1000; NSTimeInterval interval = [[NSDate date] timeIntervalSince1970] * 1000;
NSString* intervalStr = [NSString stringWithFormat:@"%f", interval]; NSString* intervalStr = [NSString stringWithFormat:@"%f", interval];
NSMutableDictionary *params = [@{@"name":key, NSMutableDictionary* params =
@"time":intervalStr [@{@"name" : key, @"time" : intervalStr} mutableCopy];
} mutableCopy];
if (!value) { if (!value) {
[params setObject:@"YES" forKey:@"deleted"]; [params setObject:@"YES" forKey:@"deleted"];
@@ -105,11 +121,12 @@ static NSString *const kAppSuiteUserDefaultsName = @"App Suite UserDefaults";
[params setObject:value forKey:@"value"]; [params setObject:value forKey:@"value"];
} }
NSString *sharedPreferencesName = (userDefaults == _standardUserDefaults NSString* sharedPreferencesName =
? kStandardUserDefaultsName (userDefaults == _standardUserDefaults ? kStandardUserDefaultsName
: kAppSuiteUserDefaultsName); : kAppSuiteUserDefaultsName);
[params setObject:sharedPreferencesName forKey:@"preferences"]; [params setObject:sharedPreferencesName forKey:@"preferences"];
[self.flipperConnection send:@"sharedPreferencesChange" withParams:[params copy]]; [self.flipperConnection send:@"sharedPreferencesChange"
withParams:[params copy]];
} }
@end @end

View File

@@ -11,7 +11,9 @@ NS_ASSUME_NONNULL_BEGIN
@interface FKUserDefaultsSwizzleUtility : NSObject @interface FKUserDefaultsSwizzleUtility : NSObject
+ (void)swizzleSelector:(SEL)selector class:(Class)aClass block:(void(^)(NSInvocation *invocation))block; + (void)swizzleSelector:(SEL)selector
class:(Class)aClass
block:(void (^)(NSInvocation* invocation))block;
@end @end

View File

@@ -22,7 +22,8 @@
_swizzledBlocks = [NSMutableDictionary dictionary]; _swizzledBlocks = [NSMutableDictionary dictionary];
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector" #pragma clang diagnostic ignored "-Wundeclared-selector"
_forwardingIMP = class_getMethodImplementation([NSObject class], @selector(flipperKitThisMethodShouldNotExist)); _forwardingIMP = class_getMethodImplementation(
[NSObject class], @selector(flipperKitThisMethodShouldNotExist));
#pragma clang diagnostic pop #pragma clang diagnostic pop
} }
return self; return self;
@@ -37,11 +38,15 @@
return sharedInstance; return sharedInstance;
} }
+ (void)swizzleSelector:(SEL)selector class:(Class)aClass block:(void (^)(NSInvocation * _Nonnull))block { + (void)swizzleSelector:(SEL)selector
class:(Class)aClass
block:(void (^)(NSInvocation* _Nonnull))block {
[[self sharedInstance] swizzleSelector:selector class:aClass block:block]; [[self sharedInstance] swizzleSelector:selector class:aClass block:block];
} }
- (void)swizzleSelector:(SEL)selector class:(Class)aClass block:(void (^)(NSInvocation * _Nonnull))blk { - (void)swizzleSelector:(SEL)selector
class:(Class)aClass
block:(void (^)(NSInvocation* _Nonnull))blk {
if (![self.swizzledClasses containsObject:aClass]) { if (![self.swizzledClasses containsObject:aClass]) {
SEL fwdSel = @selector(forwardInvocation:); SEL fwdSel = @selector(forwardInvocation:);
Method m = class_getInstanceMethod(aClass, fwdSel); Method m = class_getInstanceMethod(aClass, fwdSel);
@@ -51,7 +56,8 @@
NSString* selStr = NSStringFromSelector([invocation selector]); NSString* selStr = NSStringFromSelector([invocation selector]);
void (^block)(NSInvocation*) = weakSelf.swizzledBlocks[aClass][selStr]; void (^block)(NSInvocation*) = weakSelf.swizzledBlocks[aClass][selStr];
if (blk != nil) { if (blk != nil) {
NSString *originalStr = [@"comfacebookFlipperKit_" stringByAppendingString:selStr]; NSString* originalStr =
[@"comfacebookFlipperKit_" stringByAppendingString:selStr];
[invocation setSelector:NSSelectorFromString(originalStr)]; [invocation setSelector:NSSelectorFromString(originalStr)];
block(invocation); block(invocation);
} else { } else {
@@ -68,9 +74,11 @@
} }
classDict[NSStringFromSelector(selector)] = blk; classDict[NSStringFromSelector(selector)] = blk;
Method m = class_getInstanceMethod(aClass, selector); Method m = class_getInstanceMethod(aClass, selector);
NSString *newSelStr = [@"comfacebookFlipperKit_" stringByAppendingString:NSStringFromSelector(selector)]; NSString* newSelStr = [@"comfacebookFlipperKit_"
stringByAppendingString:NSStringFromSelector(selector)];
SEL newSel = NSSelectorFromString(newSelStr); SEL newSel = NSSelectorFromString(newSelStr);
class_addMethod(aClass, newSel, method_getImplementation(m), method_getTypeEncoding(m)); class_addMethod(
aClass, newSel, method_getImplementation(m), method_getTypeEncoding(m));
method_setImplementation(m, self.forwardingIMP); method_setImplementation(m, self.forwardingIMP);
} }
@end @end