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,36 +12,33 @@
#import <FlipperKit/FlipperResponder.h> #import <FlipperKit/FlipperResponder.h>
#import "Plugins.h" #import "Plugins.h"
@implementation FlipperKitBloksPlugin @implementation FlipperKitBloksPlugin {
{
id<FlipperConnection> _connection; id<FlipperConnection> _connection;
} }
- (void)didConnect:(id<FlipperConnection>)connection { - (void)didConnect:(id<FlipperConnection>)connection {
_connection = connection; _connection = connection;
} }
- (void)didDisconnect { - (void)didDisconnect {
_connection = nil; _connection = nil;
} }
- (NSString *)identifier { - (NSString*)identifier {
return @"flipper-plugin-bloks"; return @"flipper-plugin-bloks";
} }
- (BOOL)runInBackground { - (BOOL)runInBackground {
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,19 +5,20 @@
* 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;
- (void)triggerNotification; - (void)triggerNotification;
+ (instancetype) sharedInstance; + (instancetype)sharedInstance;
@end @end

View File

@@ -11,60 +11,62 @@
#import <FlipperKit/FlipperConnection.h> #import <FlipperKit/FlipperConnection.h>
#import <FlipperKit/FlipperResponder.h> #import <FlipperKit/FlipperResponder.h>
@interface FlipperKitExamplePlugin() @interface FlipperKitExamplePlugin ()
@property (strong, nonatomic) id<FlipperConnection> connection; @property(strong, nonatomic) id<FlipperConnection> connection;
@property (nonatomic) NSInteger triggerCount; @property(nonatomic) NSInteger triggerCount;
@end @end
@implementation FlipperKitExamplePlugin @implementation FlipperKitExamplePlugin
- (instancetype)init { - (instancetype)init {
if (self = [super init]) { if (self = [super init]) {
_triggerCount = 0; _triggerCount = 0;
} }
return self; return self;
} }
+ (instancetype)sharedInstance { + (instancetype)sharedInstance {
static FlipperKitExamplePlugin *sInstance = nil; static FlipperKitExamplePlugin* sInstance = nil;
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{
sInstance = [FlipperKitExamplePlugin new]; sInstance = [FlipperKitExamplePlugin new];
}); });
return sInstance; return sInstance;
} }
- (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"
[weakSelf.delegate messageReceived:params[@"message"]]; withBlock:^(NSDictionary* params, id<FlipperResponder> responder) {
[responder success:@{@"greeting": @"Hello"}]; [weakSelf.delegate messageReceived:params[@"message"]];
}]; [responder success:@{@"greeting" : @"Hello"}];
}];
} }
- (void)didDisconnect { - (void)didDisconnect {
self.connection = nil; self.connection = nil;
} }
- (NSString *)identifier { - (NSString*)identifier {
return @"Example"; return @"Example";
} }
- (BOOL)runInBackground { - (BOOL)runInBackground {
return YES; return YES;
} }
- (void)sendMessage:(NSString *)msg { - (void)sendMessage:(NSString*)msg {
[self.connection send:@"displayMessage" withParams:@{@"msg": msg}]; [self.connection send:@"displayMessage" withParams:@{@"msg" : msg}];
} }
- (void)triggerNotification { - (void)triggerNotification {
[self.connection send:@"triggerNotification" withParams:@{@"id": @(self.triggerCount)}]; [self.connection send:@"triggerNotification"
self.triggerCount++; withParams:@{@"id" : @(self.triggerCount)}];
self.triggerCount++;
} }
@end @end

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,12 +50,20 @@ 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]))
}] ];
} }
- (void)setMutableData:(id)data { - (void)setMutableData:(id)data {
@@ -55,15 +73,19 @@ FB_LINKABLE(CKCenterLayoutComponent_Sonar)
[self setValue:@(value.sizingOptions) forKey:@"_sizingOptions"]; [self setValue:@(value.sizingOptions) forKey:@"_sizingOptions"];
} }
- (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

@@ -14,13 +14,13 @@ typedef id (^SKNodeDataChanged)(id value);
FB_LINK_REQUIRE_CATEGORY(CKComponent_Sonar) FB_LINK_REQUIRE_CATEGORY(CKComponent_Sonar)
@interface CKComponent (Sonar) @interface CKComponent (Sonar)
@property (assign, nonatomic) NSUInteger flipper_canBeReusedCounter; @property(assign, nonatomic) NSUInteger flipper_canBeReusedCounter;
- (void)setMutableData:(id)data; - (void)setMutableData:(id)data;
- (NSDictionary<NSString *, SKNodeDataChanged> *)sonar_getDataMutationsChanged; - (NSDictionary<NSString*, SKNodeDataChanged>*)sonar_getDataMutationsChanged;
- (NSArray<SKNamed<NSDictionary<NSString *, NSObject *> *> *> *)sonar_getData; - (NSArray<SKNamed<NSDictionary<NSString*, NSObject*>*>*>*)sonar_getData;
- (NSDictionary<NSString *, SKNodeUpdateData> *)sonar_getDataMutations; - (NSDictionary<NSString*, SKNodeUpdateData>*)sonar_getDataMutations;
- (NSString *)sonar_getName; - (NSString*)sonar_getName;
- (NSString *)sonar_getDecoration; - (NSString*)sonar_getDecoration;
@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;
} }
@@ -66,98 +78,104 @@ static NSDictionary<NSString *, NSObject *> *AccessibilityContextDict(CKComponen
FB_LINKABLE(CKComponent_Sonar) FB_LINKABLE(CKComponent_Sonar)
@implementation CKComponent (Sonar) @implementation CKComponent (Sonar)
static FKDataStorageForLiveEditing *_dataStorage; 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(
replacementSEL, targetClass,
method_getImplementation(original), replacementSEL,
method_getTypeEncoding(original)); method_getImplementation(original),
method_getTypeEncoding(original));
} else { } else {
method_exchangeImplementations(original, replacement); method_exchangeImplementations(original, replacement);
} }
} }
- (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", @(UIControlEventTouchDragInside) : @"UIControlEventTouchDragInside",
@(UIControlEventTouchDragInside): @"UIControlEventTouchDragInside", @(UIControlEventTouchDragOutside) : @"UIControlEventTouchDragOutside",
@(UIControlEventTouchDragOutside): @"UIControlEventTouchDragOutside", @(UIControlEventTouchDragEnter) : @"UIControlEventTouchDragEnter",
@(UIControlEventTouchDragEnter): @"UIControlEventTouchDragEnter", @(UIControlEventTouchDragExit) : @"UIControlEventTouchDragExit",
@(UIControlEventTouchDragExit): @"UIControlEventTouchDragExit", @(UIControlEventTouchUpInside) : @"UIControlEventTouchUpInside",
@(UIControlEventTouchUpInside): @"UIControlEventTouchUpInside", @(UIControlEventTouchUpOutside) : @"UIControlEventTouchUpOutside",
@(UIControlEventTouchUpOutside): @"UIControlEventTouchUpOutside", @(UIControlEventTouchCancel) : @"UIControlEventTouchTouchCancel",
@(UIControlEventTouchCancel): @"UIControlEventTouchTouchCancel",
@(UIControlEventValueChanged): @"UIControlEventValueChanged", @(UIControlEventValueChanged) : @"UIControlEventValueChanged",
@(UIControlEventPrimaryActionTriggered): @"UIControlEventPrimaryActionTriggered", @(UIControlEventPrimaryActionTriggered) :
@"UIControlEventPrimaryActionTriggered",
@(UIControlEventEditingDidBegin): @"UIControlEventEditingDidBegin", @(UIControlEventEditingDidBegin) : @"UIControlEventEditingDidBegin",
@(UIControlEventEditingChanged): @"UIControlEventEditingChanged", @(UIControlEventEditingChanged) : @"UIControlEventEditingChanged",
@(UIControlEventEditingDidEnd): @"UIControlEventEditingDidEnd", @(UIControlEventEditingDidEnd) : @"UIControlEventEditingDidEnd",
@(UIControlEventEditingDidEndOnExit): @"UIControlEventEditingDidEndOnExit", @(UIControlEventEditingDidEndOnExit) : @"UIControlEventEditingDidEndOnExit",
}; };
NSMutableArray<SKNamed<NSDictionary<NSString*, NSObject*>*>*>* data =
[NSMutableArray new];
NSMutableArray<SKNamed<NSDictionary<NSString *, NSObject *> *> *> *data = [NSMutableArray new]; [data addObject:[SKNamed newWithName:@"CKComponent"
withValue:@{
[data addObject: [SKNamed newWithName: @"CKComponent" @"frame" : SKObject(self.viewContext.frame),
withValue: @{ @"controller" : SKObject(
@"frame": SKObject(self.viewContext.frame), 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
withValue: @{ newWithName:@"Convert to CKRenderComponent"
@"This component can be reused" : withValue:@{
SKObject([NSString stringWithFormat:@"%lu times", (unsigned long)canBeReusedCounter]) @"This component can be reused" : SKObject([NSString
}]]; 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) {
@@ -167,20 +185,25 @@ static CK::StaticMutex _mutex = CK_MUTEX_INITIALIZER;
for (auto responder : action.second) { for (auto responder : action.second) {
auto debugTarget = _CKTypedComponentDebugInitialTarget(responder); auto debugTarget = _CKTypedComponentDebugInitialTarget(responder);
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 =
[responders addObject: @{ CKActionFind(responder.selector(), initialTarget);
@"initialTarget": SKObject(NSStringFromClass([initialTarget class])), [responders addObject:@{
@"identifier": SKObject(@(responder.identifier().c_str())), @"initialTarget" :
@"handler": SKObject(NSStringFromClass([actionInfo.responder class])), SKObject(NSStringFromClass([initialTarget class])),
@"selector": SKObject(NSStringFromSelector(responder.selector())), @"identifier" : SKObject(@(responder.identifier().c_str())),
}]; @"handler" :
SKObject(NSStringFromClass([actionInfo.responder class])),
@"selector" :
SKObject(NSStringFromSelector(responder.selector())),
}];
} }
} }
} }
@@ -190,19 +213,23 @@ static CK::StaticMutex _mutex = CK_MUTEX_INITIALIZER;
} }
} }
[data addObject: [SKNamed newWithName: @"Actions" withValue: actions]]; [data addObject:[SKNamed newWithName:@"Actions" withValue:actions]];
} }
} }
// 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)]) {
[data addObjectsFromArray:[(id)self sonar_additionalDataOverride]]; [data addObjectsFromArray:[(id)self sonar_additionalDataOverride]];
@@ -212,10 +239,9 @@ static CK::StaticMutex _mutex = CK_MUTEX_INITIALIZER;
} }
- (void)setMutableData:(id)value { - (void)setMutableData:(id)value {
} }
- (void) setMutableDataFromStorage { - (void)setMutableDataFromStorage {
const auto globalID = self.treeNode.nodeIdentifier; const auto globalID = self.treeNode.nodeIdentifier;
id data = [_dataStorage dataForTreeNodeIdentifier:globalID]; id data = [_dataStorage dataForTreeNodeIdentifier:globalID];
if (data) { if (data) {
@@ -223,32 +249,36 @@ 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(
resultSelector, self,
method_getImplementation(method), resultSelector,
method_getTypeEncoding(method) method_getImplementation(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 {
return @{}; return @{};
} }
- (NSDictionary<NSString *, SKNodeUpdateData> *)sonar_getDataMutations { - (NSDictionary<NSString*, SKNodeUpdateData>*)sonar_getDataMutations {
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{
_dataStorage = [[FKDataStorageForLiveEditing alloc] init]; _dataStorage = [[FKDataStorageForLiveEditing alloc] init];
@@ -259,46 +289,55 @@ 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 =
NSMutableDictionary *dataMutation = [[NSMutableDictionary alloc] init]; [self sonar_getDataMutationsChanged];
NSMutableDictionary* dataMutation = [[NSMutableDictionary alloc] init];
[dataMutation addEntriesFromDictionary:@{ [dataMutation addEntriesFromDictionary:@{
@"Accessibility.accessibilityEnabled": ^(NSNumber *value) { @"Accessibility.accessibilityEnabled": ^(NSNumber *value) {
CK::Component::Accessibility::SetForceAccessibilityEnabled([value boolValue]); CK::Component::Accessibility::SetForceAccessibilityEnabled([value boolValue]);
} }
} }
]; ];
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
id data = block(value); setObject:^(id value) {
[_dataStorage setData:data forTreeNodeIdentifier:globalID]; id data = block(value);
[CKComponentDebugController reflowComponentsWithTreeNodeIdentifier:globalID]; [_dataStorage setData:data forTreeNodeIdentifier:globalID];
} [CKComponentDebugController
forKey:key]; reflowComponentsWithTreeNodeIdentifier:globalID];
} }
return dataMutation; forKey:key];
} }
return dataMutation;
}
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
#endif #endif

View File

@@ -18,69 +18,72 @@
FB_LINKABLE(CKFlexboxComponent_Sonar) FB_LINKABLE(CKFlexboxComponent_Sonar)
@implementation CKFlexboxComponent (Sonar) @implementation CKFlexboxComponent (Sonar)
static NSDictionary<NSNumber *, NSString *> *CKFlexboxDirectionEnumMap; static NSDictionary<NSNumber*, NSString*>* CKFlexboxDirectionEnumMap;
static NSDictionary<NSNumber *, NSString *> *CKFlexboxJustifyContentEnumMap; static NSDictionary<NSNumber*, NSString*>* CKFlexboxJustifyContentEnumMap;
static NSDictionary<NSNumber *, NSString *> *CKFlexboxAlignItemsEnumMap; static NSDictionary<NSNumber*, NSString*>* CKFlexboxAlignItemsEnumMap;
static NSDictionary<NSNumber *, NSString *> *CKFlexboxAlignContentEnumMap; 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",
@(CKFlexboxDirectionColumnReverse): @"column-reverse", @(CKFlexboxDirectionColumnReverse) : @"column-reverse",
@(CKFlexboxDirectionRowReverse): @"row-reverse", @(CKFlexboxDirectionRowReverse) : @"row-reverse",
}; };
CKFlexboxJustifyContentEnumMap = @{ CKFlexboxJustifyContentEnumMap = @{
@(CKFlexboxJustifyContentStart): @"start", @(CKFlexboxJustifyContentStart) : @"start",
@(CKFlexboxJustifyContentCenter): @"center", @(CKFlexboxJustifyContentCenter) : @"center",
@(CKFlexboxJustifyContentEnd): @"end", @(CKFlexboxJustifyContentEnd) : @"end",
@(CKFlexboxJustifyContentSpaceBetween): @"space-between", @(CKFlexboxJustifyContentSpaceBetween) : @"space-between",
@(CKFlexboxJustifyContentSpaceAround): @"space-around", @(CKFlexboxJustifyContentSpaceAround) : @"space-around",
}; };
CKFlexboxAlignItemsEnumMap = @{ CKFlexboxAlignItemsEnumMap = @{
@(CKFlexboxAlignItemsStart): @"start", @(CKFlexboxAlignItemsStart) : @"start",
@(CKFlexboxAlignItemsEnd): @"end", @(CKFlexboxAlignItemsEnd) : @"end",
@(CKFlexboxAlignItemsCenter): @"center", @(CKFlexboxAlignItemsCenter) : @"center",
@(CKFlexboxAlignItemsBaseline): @"baseline", @(CKFlexboxAlignItemsBaseline) : @"baseline",
@(CKFlexboxAlignItemsStretch): @"stretch", @(CKFlexboxAlignItemsStretch) : @"stretch",
}; };
CKFlexboxAlignContentEnumMap = @{ CKFlexboxAlignContentEnumMap = @{
@(CKFlexboxAlignContentStart): @"start", @(CKFlexboxAlignContentStart) : @"start",
@(CKFlexboxAlignContentEnd): @"end", @(CKFlexboxAlignContentEnd) : @"end",
@(CKFlexboxAlignContentCenter): @"center", @(CKFlexboxAlignContentCenter) : @"center",
@(CKFlexboxAlignContentSpaceBetween): @"space-between", @(CKFlexboxAlignContentSpaceBetween) : @"space-between",
@(CKFlexboxAlignContentSpaceAround): @"space-around", @(CKFlexboxAlignContentSpaceAround) : @"space-around",
@(CKFlexboxAlignContentStretch): @"stretch", @(CKFlexboxAlignContentStretch) : @"stretch",
}; };
CKFlexboxWrapEnumMap = @{ CKFlexboxWrapEnumMap = @{
@(CKFlexboxWrapWrap): @"wrap", @(CKFlexboxWrapWrap) : @"wrap",
@(CKFlexboxWrapNoWrap): @"no-wrap", @(CKFlexboxWrapNoWrap) : @"no-wrap",
@(CKFlexboxWrapWrapReverse): @"wrap-reverse", @(CKFlexboxWrapWrapReverse) : @"wrap-reverse",
}; };
} }
- (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];
return @[[SKNamed return @[ [SKNamed
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)]),
@"wrap": SKMutableObject(CKFlexboxWrapEnumMap[@(style.wrap)]), @"alignItems" :
@"padding": SKMutableObject(flexboxRect(style.padding)), SKMutableObject(CKFlexboxAlignItemsEnumMap[@(style.alignItems)]),
}]]; @"alignContent" : SKMutableObject(
CKFlexboxAlignContentEnumMap[@(style.alignContent)]),
@"wrap" : SKMutableObject(CKFlexboxWrapEnumMap[@(style.wrap)]),
@"padding" : SKMutableObject(flexboxRect(style.padding)),
}] ];
} }
- (void)setMutableData:(id)data { - (void)setMutableData:(id)data {
@@ -89,14 +92,14 @@ static NSDictionary<NSNumber *, NSString *> *CKFlexboxWrapEnumMap;
[self setValue:data forKey:@"_style"]; [self setValue:data forKey:@"_style"];
} }
- (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,22 +17,27 @@
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 {
[self setValue:data forKey:@"_insets"]; [self setValue:data forKey:@"_insets"];
} }
- (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,23 +17,28 @@
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 {
[self setValue:data forKey:@"_ratio"]; [self setValue:data forKey:@"_ratio"];
} }
- (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

@@ -11,6 +11,6 @@
FB_LINK_REQUIRE_CATEGORY(CKStatelessComponent_Sonar) FB_LINK_REQUIRE_CATEGORY(CKStatelessComponent_Sonar)
@interface CKStatelessComponent (Sonar) @interface CKStatelessComponent (Sonar)
- (NSString *)sonar_componentNameOverride; - (NSString*)sonar_componentNameOverride;
@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

@@ -7,11 +7,12 @@
#import <ComponentKit/CKTreeNodeTypes.h> #import <ComponentKit/CKTreeNodeTypes.h>
/** DataStorage uses to map global IDs of nodes to data which we want to store /** DataStorage uses to map global IDs of nodes to data which we want to store
to prodice live editing*/ 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,14 +7,14 @@
#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
+ (void)setUpWithDescriptorMapper:(SKDescriptorMapper *)mapper; + (void)setUpWithDescriptorMapper:(SKDescriptorMapper*)mapper;
+ (void)setUpWithDescriptorMapper:(SKDescriptorMapper *)mapper + (void)setUpWithDescriptorMapper:(SKDescriptorMapper*)mapper
subDescriptors:(NSArray<SKSubDescriptor *>*)subDescriptors; subDescriptors:(NSArray<SKSubDescriptor*>*)subDescriptors;
@end @end

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]
forClass: [CKComponentHostingView class]]; initWithDescriptorMapper:mapper]
[mapper registerDescriptor: [[SKComponentRootViewDescriptor alloc] initWithDescriptorMapper: mapper] forClass:[CKComponentHostingView class]];
forClass: [CKComponentRootView class]]; [mapper registerDescriptor:[[SKComponentRootViewDescriptor alloc]
SKComponentLayoutDescriptor *layoutDescriptor = [[SKComponentLayoutDescriptor alloc] initWithDescriptorMapper:mapper]; initWithDescriptorMapper:mapper]
forClass:[CKComponentRootView class]];
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.
forClass: [CKComponentHostingView class]]; [mapper registerDescriptor:[[SKComponentHostingViewDescriptor alloc]
[mapper registerDescriptor: [[SKComponentRootViewDescriptor alloc] initWithDescriptorMapper: mapper] initWithDescriptorMapper:mapper]
forClass: [CKComponentRootView class]]; forClass:[CKComponentHostingView class]];
[mapper registerDescriptor: [[SKComponentLayoutDescriptor alloc] initWithDescriptorMapper: mapper] [mapper registerDescriptor:[[SKComponentRootViewDescriptor alloc]
forClass: [SKComponentLayoutWrapper class]]; initWithDescriptorMapper:mapper]
forClass:[CKComponentRootView class]];
[mapper registerDescriptor:[[SKComponentLayoutDescriptor alloc]
initWithDescriptorMapper:mapper]
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>
@@ -21,25 +20,25 @@
@implementation SKComponentHostingViewDescriptor @implementation SKComponentHostingViewDescriptor
- (NSString *)identifierForNode:(CKComponentHostingView *)node { - (NSString*)identifierForNode:(CKComponentHostingView*)node {
return [NSString stringWithFormat: @"%p", node]; return [NSString stringWithFormat:@"%p", node];
} }
- (NSUInteger)childCountForNode:(CKComponentHostingView *)node { - (NSUInteger)childCountForNode:(CKComponentHostingView*)node {
return node.mountedLayout.component ? 1 : 0; return node.mountedLayout.component ? 1 : 0;
} }
- (id)childForNode:(CKComponentHostingView *)node atIndex:(NSUInteger)index { - (id)childForNode:(CKComponentHostingView*)node atIndex:(NSUInteger)index {
return [SKComponentLayoutWrapper newFromRoot:node]; return [SKComponentLayoutWrapper newFromRoot:node];
} }
- (void)setHighlighted:(BOOL)highlighted forNode:(CKComponentHostingView *)node { - (void)setHighlighted:(BOOL)highlighted forNode:(CKComponentHostingView*)node {
SKNodeDescriptor *viewDescriptor = [self descriptorForClass: [UIView class]]; SKNodeDescriptor* viewDescriptor = [self descriptorForClass:[UIView class]];
[viewDescriptor setHighlighted: highlighted forNode: node]; [viewDescriptor setHighlighted:highlighted forNode:node];
} }
- (void)hitTest:(SKTouch *)touch forNode:(CKComponentHostingView *)node { - (void)hitTest:(SKTouch*)touch forNode:(CKComponentHostingView*)node {
[touch continueWithChildIndex: 0 withOffset: (CGPoint){ 0, 0 }]; [touch continueWithChildIndex:0 withOffset:(CGPoint){0, 0}];
} }
@end @end

View File

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

View File

@@ -10,30 +10,29 @@
#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;
} }
- (void)setUp { - (void)setUp {
@@ -51,38 +50,37 @@
- (void)initEnumMaps { - (void)initEnumMaps {
CKFlexboxAlignSelfEnumMap = @{ CKFlexboxAlignSelfEnumMap = @{
@(CKFlexboxAlignSelfAuto): @"auto", @(CKFlexboxAlignSelfAuto) : @"auto",
@(CKFlexboxAlignSelfStart): @"start", @(CKFlexboxAlignSelfStart) : @"start",
@(CKFlexboxAlignSelfEnd): @"end", @(CKFlexboxAlignSelfEnd) : @"end",
@(CKFlexboxAlignSelfCenter): @"center", @(CKFlexboxAlignSelfCenter) : @"center",
@(CKFlexboxAlignSelfBaseline): @"baseline", @(CKFlexboxAlignSelfBaseline) : @"baseline",
@(CKFlexboxAlignSelfStretch): @"stretch", @(CKFlexboxAlignSelfStretch) : @"stretch",
}; };
CKFlexboxPositionTypeEnumMap = @{ CKFlexboxPositionTypeEnumMap = @{
@(CKFlexboxPositionTypeRelative): @"relative", @(CKFlexboxPositionTypeRelative) : @"relative",
@(CKFlexboxPositionTypeAbsolute): @"absolute", @(CKFlexboxPositionTypeAbsolute) : @"absolute",
}; };
} }
- (NSString *)identifierForNode:(SKComponentLayoutWrapper *)node { - (NSString*)identifierForNode:(SKComponentLayoutWrapper*)node {
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];
} }
- (NSString *)nameForNode:(SKComponentLayoutWrapper *)node { - (NSString*)nameForNode:(SKComponentLayoutWrapper*)node {
return [node.component sonar_getName]; return [node.component sonar_getName];
} }
- (NSString *)decorationForNode:(SKComponentLayoutWrapper *)node { - (NSString*)decorationForNode:(SKComponentLayoutWrapper*)node {
return [node.component sonar_getDecoration]; return [node.component sonar_getDecoration];
} }
- (NSUInteger)childCountForNode:(SKComponentLayoutWrapper *)node { - (NSUInteger)childCountForNode:(SKComponentLayoutWrapper*)node {
NSUInteger count = node.children.size(); NSUInteger count = node.children.size();
if (count == 0) { if (count == 0) {
count = node.component.viewContext.view ? 1 : 0; count = node.component.viewContext.view ? 1 : 0;
@@ -90,93 +88,107 @@
return count; return count;
} }
- (id)childForNode:(SKComponentLayoutWrapper *)node atIndex:(NSUInteger)index { - (id)childForNode:(SKComponentLayoutWrapper*)node atIndex:(NSUInteger)index {
if (node.children.size() == 0) { if (node.children.size() == 0) {
if (node.rootNode == node.component.viewContext.view) { if (node.rootNode == node.component.viewContext.view) {
return nil; return nil;
}
return node.component.viewContext.view;
} }
return node.children[index]; return node.component.viewContext.view;
}
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]];
return data; return data;
} }
- (void)addSubDescriptors:(nonnull NSArray<SKSubDescriptor *>*)subDescriptors{ - (void)addSubDescriptors:(nonnull NSArray<SKSubDescriptor*>*)subDescriptors {
_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)),
@"flexGrow": SKObject(@(child.flexGrow)), @"flexGrow" : SKObject(@(child.flexGrow)),
@"flexShrink": SKObject(@(child.flexShrink)), @"flexShrink" : SKObject(@(child.flexShrink)),
@"zIndex": SKObject(@(child.zIndex)), @"zIndex" : SKObject(@(child.zIndex)),
@"sizeConstraints": SKObject(ckcomponentSize(child.sizeConstraints)), @"sizeConstraints" : SKObject(ckcomponentSize(child.sizeConstraints)),
@"useTextRounding": SKObject(@(child.useTextRounding)), @"useTextRounding" : SKObject(@(child.useTextRounding)),
@"margin": flexboxRect(child.margin), @"margin" : flexboxRect(child.margin),
@"flexBasis": relativeDimension(child.flexBasis), @"flexBasis" : relativeDimension(child.flexBasis),
@"padding": flexboxRect(child.padding), @"padding" : flexboxRect(child.padding),
@"alignSelf": CKFlexboxAlignSelfEnumMap[@(child.alignSelf)], @"alignSelf" : CKFlexboxAlignSelfEnumMap[@(child.alignSelf)],
@"position": @{ @"position" : @{
@"type": CKFlexboxPositionTypeEnumMap[@(child.position.type)], @"type" : CKFlexboxPositionTypeEnumMap[@(child.position.type)],
@"start": relativeDimension(child.position.start), @"start" : relativeDimension(child.position.start),
@"top": relativeDimension(child.position.top), @"top" : relativeDimension(child.position.top),
@"end": relativeDimension(child.position.end), @"end" : relativeDimension(child.position.end),
@"bottom": relativeDimension(child.position.bottom), @"bottom" : relativeDimension(child.position.bottom),
@"left": relativeDimension(child.position.left), @"left" : relativeDimension(child.position.left),
@"right": relativeDimension(child.position.right), @"right" : relativeDimension(child.position.right),
}, },
@"aspectRatio": @(child.aspectRatio.aspectRatio()), @"aspectRatio" : @(child.aspectRatio.aspectRatio()),
}; };
} }
- (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:
NSMutableArray<SKNamed<NSString *> *> *attributes = [NSMutableArray array]; (SKComponentLayoutWrapper*)node {
[attributes addObject:[SKNamed newWithName:@"responder" NSMutableArray<SKNamed<NSString*>*>* attributes = [NSMutableArray array];
withValue:SKObject(NSStringFromClass([node.component.nextResponder class]))]]; [attributes
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
SKHighlightOverlay *overlay = [SKHighlightOverlay sharedInstance]; forNode:(SKComponentLayoutWrapper*)node {
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];
} }
} }
- (void)hitTest:(SKTouch *)touch forNode:(SKComponentLayoutWrapper *)node { - (void)hitTest:(SKTouch*)touch forNode:(SKComponentLayoutWrapper*)node {
if (node.children.size() == 0) { if (node.children.size() == 0) {
UIView *componentView = node.component.viewContext.view; UIView* componentView = node.component.viewContext.view;
if (componentView != nil) { if (componentView != nil) {
if ([touch containedIn: componentView.bounds]) { if ([touch containedIn:componentView.bounds]) {
[touch continueWithChildIndex: 0 withOffset: componentView.bounds.origin]; [touch continueWithChildIndex:0 withOffset:componentView.bounds.origin];
return; return;
} }
} }
@@ -186,13 +198,10 @@
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];
return; return;
} }
} }
@@ -200,22 +209,26 @@
[touch finish]; [touch finish];
} }
- (BOOL)matchesQuery:(NSString *)query forNode:(id)node { - (BOOL)matchesQuery:(NSString*)query forNode:(id)node {
if ([super matchesQuery:query forNode:node]) { if ([super matchesQuery:query forNode:node]) {
return YES; return YES;
}
if ([node isKindOfClass:[SKComponentLayoutWrapper class]]) {
const auto layoutWrapper = (SKComponentLayoutWrapper*)node;
if ([layoutWrapper.component
conformsToProtocol:@protocol(FKTextSearchable)]) {
NSString* text =
((id<FKTextSearchable>)layoutWrapper.component).searchableText;
return [self string:text contains:query];
} }
if ([node isKindOfClass:[SKComponentLayoutWrapper class]]) { }
const auto layoutWrapper = (SKComponentLayoutWrapper *)node; return NO;
if ([layoutWrapper.component conformsToProtocol:@protocol(FKTextSearchable)]) {
NSString *text = ((id<FKTextSearchable>)layoutWrapper.component).searchableText;
return [self string:text contains:query];
}
}
return NO;
} }
- (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

@@ -14,17 +14,18 @@
@interface SKComponentLayoutWrapper : NSObject @interface SKComponentLayoutWrapper : NSObject
@property (nonatomic, weak, readonly) CKComponent *component; @property(nonatomic, weak, readonly) CKComponent* component;
@property (nonatomic, readonly) NSString *identifier; @property(nonatomic, readonly) NSString* identifier;
@property (nonatomic, readonly) CGSize size; @property(nonatomic, readonly) CGSize size;
@property (nonatomic, readonly) CGPoint position; @property(nonatomic, readonly) CGPoint position;
@property (nonatomic, readonly) std::vector<SKComponentLayoutWrapper *> children; @property(nonatomic, readonly) std::vector<SKComponentLayoutWrapper*> children;
@property (nonatomic, weak, readonly) id<CKInspectableView> rootNode; @property(nonatomic, weak, readonly) id<CKInspectableView> rootNode;
// Null for layouts which are not direct children of a CKFlexboxComponent // Null for layouts which are not direct children of a CKFlexboxComponent
@property (nonatomic, readonly) BOOL isFlexboxChild; @property(nonatomic, readonly) BOOL isFlexboxChild;
@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,47 +51,59 @@ 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
reuseWrapper:reuseWrapper stringWithFormat:@"%@%d.",
rootNode: root]; parentKey,
component.treeNode.nodeIdentifier]
reuseWrapper:reuseWrapper
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;
} }
- (instancetype)initWithLayout:(const CKComponentLayout &)layout - (instancetype)initWithLayout:(const CKComponentLayout&)layout
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;
} }
@@ -95,18 +111,22 @@ static CKFlexboxComponentChild findFlexboxLayoutParams(CKComponent *parent, CKCo
if (layout.children != nullptr) { if (layout.children != nullptr) {
int index = 0; int index = 0;
for (const auto &child : *layout.children) { for (const auto& child : *layout.children) {
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 =
position:child.position [[SKComponentLayoutWrapper alloc]
parentKey:[_identifier stringByAppendingFormat:@"[%d].", index++] initWithLayout:child.layout
reuseWrapper:reuseWrapper position:child.position
rootNode:node parentKey:[_identifier
]; stringByAppendingFormat:@"[%d].", index++]
childWrapper->_isFlexboxChild = [_component isKindOfClass:[CKFlexboxComponent class]]; reuseWrapper:reuseWrapper
childWrapper->_flexboxChild = findFlexboxLayoutParams(_component, (CKComponent *)child.layout.component); rootNode:node];
childWrapper->_isFlexboxChild =
[_component isKindOfClass:[CKFlexboxComponent class]];
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

@@ -22,28 +22,30 @@
@implementation SKComponentRootViewDescriptor @implementation SKComponentRootViewDescriptor
- (NSString *)identifierForNode:(CKComponentRootView *)node { - (NSString*)identifierForNode:(CKComponentRootView*)node {
return [NSString stringWithFormat: @"%p", node]; return [NSString stringWithFormat:@"%p", node];
} }
- (NSUInteger)childCountForNode:(CKComponentRootView *)node { - (NSUInteger)childCountForNode:(CKComponentRootView*)node {
const auto state = CKGetAttachStateForView(node); const auto state = CKGetAttachStateForView(node);
return state == nil ? 0 : 1; return state == nil ? 0 : 1;
} }
- (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 {
SKNodeDescriptor *viewDescriptor = [self descriptorForClass: [UIView class]]; SKNodeDescriptor* viewDescriptor = [self descriptorForClass:[UIView class]];
[viewDescriptor setHighlighted: highlighted forNode: node]; [viewDescriptor setHighlighted:highlighted forNode:node];
} }
- (void)hitTest:(SKTouch *)touch forNode:(CKComponentRootView *)node { - (void)hitTest:(SKTouch*)touch forNode:(CKComponentRootView*)node {
[touch continueWithChildIndex: 0 withOffset: (CGPoint){ 0, 0 }]; [touch continueWithChildIndex:0 withOffset:(CGPoint){0, 0}];
} }
@end @end

View File

@@ -11,19 +11,19 @@
/** /**
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
/** /**
This is the SubDescriptor name. This is the SubDescriptor name.
*/ */
- (NSString *) getName; - (NSString*)getName;
/** /**
This is the data the SubDescriptor wants to pass up to the SKLayoutDescriptor. This is the data the SubDescriptor wants to pass up to the SKLayoutDescriptor.
*/ */
- (NSString *)getDataForNode:(SKComponentLayoutWrapper *)node; - (NSString*)getDataForNode:(SKComponentLayoutWrapper*)node;
@end @end

View File

@@ -10,15 +10,15 @@
#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 @{};
} }
- (NSString *)getName { - (NSString*)getName {
return @""; return @"";
} }

View File

@@ -8,7 +8,7 @@
#import <ComponentKit/CKComponent.h> #import <ComponentKit/CKComponent.h>
#import <ComponentKit/CKFlexboxComponent.h> #import <ComponentKit/CKFlexboxComponent.h>
NSString *relativeDimension(CKRelativeDimension dimension); NSString* relativeDimension(CKRelativeDimension dimension);
NSDictionary<NSString *, NSString *> *flexboxRect(CKFlexboxSpacing spacing); NSDictionary<NSString*, NSString*>* flexboxRect(CKFlexboxSpacing spacing);
CKRelativeDimension relativeStructDimension(NSString *dimension); CKRelativeDimension relativeStructDimension(NSString* dimension);
NSDictionary<NSString *, NSString *> *ckcomponentSize(CKComponentSize size); NSDictionary<NSString*, NSString*>* ckcomponentSize(CKComponentSize size);

View File

@@ -9,44 +9,46 @@
#include "Utils.h" #include "Utils.h"
NSString *relativeDimension(CKRelativeDimension dimension) { NSString* relativeDimension(CKRelativeDimension dimension) {
switch(dimension.type()) { switch (dimension.type()) {
case CKRelativeDimension::Type::PERCENT: case CKRelativeDimension::Type::PERCENT:
return [NSString stringWithFormat: @"%@%%", @(dimension.value())]; return [NSString stringWithFormat:@"%@%%", @(dimension.value())];
case CKRelativeDimension::Type::POINTS: case CKRelativeDimension::Type::POINTS:
return [NSString stringWithFormat: @"%@pt", @(dimension.value())]; return [NSString stringWithFormat:@"%@pt", @(dimension.value())];
default: default:
return @"auto"; return @"auto";
} }
} }
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();
} }
NSDictionary<NSString *, NSString *> *flexboxRect(CKFlexboxSpacing spacing) { NSDictionary<NSString*, NSString*>* flexboxRect(CKFlexboxSpacing spacing) {
return @{ return @{
@"top": relativeDimension(spacing.top.dimension()), @"top" : relativeDimension(spacing.top.dimension()),
@"bottom": relativeDimension(spacing.bottom.dimension()), @"bottom" : relativeDimension(spacing.bottom.dimension()),
@"start": relativeDimension(spacing.start.dimension()), @"start" : relativeDimension(spacing.start.dimension()),
@"end": relativeDimension(spacing.end.dimension()) @"end" : relativeDimension(spacing.end.dimension())
}; };
} }
NSDictionary<NSString *, NSString *> *ckcomponentSize(CKComponentSize size) { NSDictionary<NSString*, NSString*>* ckcomponentSize(CKComponentSize size) {
return @{ return @{
@"width": relativeDimension(size.width), @"width" : relativeDimension(size.width),
@"height": relativeDimension(size.height), @"height" : relativeDimension(size.height),
@"minWidth": relativeDimension(size.minWidth), @"minWidth" : relativeDimension(size.minWidth),
@"minHeight": relativeDimension(size.minHeight), @"minHeight" : relativeDimension(size.minHeight),
@"maxWidth": relativeDimension(size.maxWidth), @"maxWidth" : relativeDimension(size.maxWidth),
@"maxHeight": relativeDimension(size.maxHeight), @"maxHeight" : relativeDimension(size.maxHeight),
}; };
} }

View File

@@ -11,20 +11,21 @@
#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;
- (instancetype)initWithRootNode:(id<NSObject>)rootNode - (instancetype)initWithRootNode:(id<NSObject>)rootNode
withTapListener:(id<SKTapListener>)tapListener withTapListener:(id<SKTapListener>)tapListener
withDescriptorMapper:(SKDescriptorMapper *)mapper; withDescriptorMapper:(SKDescriptorMapper*)mapper;
@property (nonatomic, readonly, strong) SKDescriptorMapper *descriptorMapper; @property(nonatomic, readonly, strong) SKDescriptorMapper* descriptorMapper;
@end @end

View File

@@ -13,21 +13,19 @@
#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;
NSString* _lastHighlightedNode;
NSMapTable<NSString *, id> *_trackedObjects; NSMutableSet* _invalidObjects;
NSString *_lastHighlightedNode;
NSMutableSet *_invalidObjects;
Boolean _invalidateMessageQueued; Boolean _invalidateMessageQueued;
NSDate *_lastInvalidateMessage; NSDate* _lastInvalidateMessage;
std::mutex invalidObjectsMutex; std::mutex invalidObjectsMutex;
id<NSObject> _rootNode; id<NSObject> _rootNode;
@@ -35,19 +33,19 @@
id<FlipperConnection> _connection; id<FlipperConnection> _connection;
NSMutableSet *_registeredDelegates; NSMutableSet* _registeredDelegates;
} }
- (instancetype)initWithRootNode:(id<NSObject>)rootNode - (instancetype)initWithRootNode:(id<NSObject>)rootNode
withDescriptorMapper:(SKDescriptorMapper *)mapper{ withDescriptorMapper:(SKDescriptorMapper*)mapper {
return [self initWithRootNode: rootNode return [self initWithRootNode:rootNode
withTapListener: [SKTapListenerImpl new] withTapListener:[SKTapListenerImpl new]
withDescriptorMapper: mapper]; withDescriptorMapper:mapper];
} }
- (instancetype)initWithRootNode:(id<NSObject>)rootNode - (instancetype)initWithRootNode:(id<NSObject>)rootNode
withTapListener:(id<SKTapListener>)tapListener withTapListener:(id<SKTapListener>)tapListener
withDescriptorMapper:(SKDescriptorMapper *)mapper { withDescriptorMapper:(SKDescriptorMapper*)mapper {
if (self = [super init]) { if (self = [super init]) {
_descriptorMapper = mapper; _descriptorMapper = mapper;
_trackedObjects = [NSMapTable strongToWeakObjectsMapTable]; _trackedObjects = [NSMapTable strongToWeakObjectsMapTable];
@@ -65,203 +63,279 @@
return self; return self;
} }
- (NSString *)identifier - (NSString*)identifier {
{
return @"Inspector"; return @"Inspector";
} }
- (void)didConnect:(id<FlipperConnection>)connection { - (void)didConnect:(id<FlipperConnection>)connection {
_connection = connection; _connection = connection;
if (!_rootNode) { if (!_rootNode) {
// TODO: T61384369 get rid off this if condition. // TODO: T61384369 get rid off this if condition.
_rootNode = [UIApplication sharedApplication]; _rootNode = [UIApplication sharedApplication];
} }
[SKInvalidation enableInvalidations]; [SKInvalidation enableInvalidations];
// Run setup logic for each descriptor // Run setup logic for each descriptor
for (SKNodeDescriptor *descriptor in _descriptorMapper.allDescriptors) { for (SKNodeDescriptor* descriptor in _descriptorMapper.allDescriptors) {
[descriptor setUp]; [descriptor setUp];
} }
// In order to avoid a retain cycle (Connection -> Block -> FlipperKitLayoutPlugin -> Connection ...) // In order to avoid a retain cycle (Connection -> Block ->
__weak FlipperKitLayoutPlugin *weakSelf = self; // FlipperKitLayoutPlugin -> Connection ...)
__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) {
[weakSelf onCallSetData: params[@"id"] FlipperPerformBlockOnMainThread(
withPath: params[@"path"] ^{
toValue: params[@"value"] [weakSelf onCallSetData:params[@"id"]
withConnection: connection]; withPath:params[@"path"]
}, responder); toValue:params[@"value"]
}]; withConnection:connection];
},
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);
}];
} }
- (void)didDisconnect { - (void)didDisconnect {
// Clear the last highlight if there is any // Clear the last highlight if there is any
[self onCallSetHighlighted: nil withResponder: nil]; [self onCallSetHighlighted:nil withResponder:nil];
// Disable search if it is active // Disable search if it is active
[self onCallSetSearchActive: NO withConnection: nil]; [self onCallSetSearchActive:NO withConnection:nil];
} }
- (void)onCallGetRoot:(id<FlipperResponder>)responder { - (void)onCallGetRoot:(id<FlipperResponder>)responder {
const auto rootNode= [self getNode: [self trackObject: _rootNode]]; const auto rootNode = [self getNode:[self trackObject:_rootNode]];
[responder success: rootNode]; [responder success:rootNode];
} }
- (void)populateAllNodesFromNode:(nonnull NSString *)identifier inDictionary:(nonnull NSMutableDictionary<NSString*, NSDictionary*> *)mutableDict { - (void)populateAllNodesFromNode:(nonnull NSString*)identifier
NSDictionary *nodeDict = [self getNode:identifier]; inDictionary:
(nonnull NSMutableDictionary<NSString*, NSDictionary*>*)
mutableDict {
NSDictionary* nodeDict = [self getNode:identifier];
mutableDict[identifier] = nodeDict; mutableDict[identifier] = nodeDict;
NSArray *arr = nodeDict[@"children"]; NSArray* arr = nodeDict[@"children"];
for (NSString *childIdentifier in arr) { for (NSString* childIdentifier in arr) {
[self populateAllNodesFromNode:childIdentifier inDictionary:mutableDict]; [self populateAllNodesFromNode:childIdentifier inDictionary:mutableDict];
} }
return; return;
} }
- (void)populateAllNodesFromNode:(nonnull NSString *)identifier inArray:(nonnull NSMutableArray<NSDictionary *> *)mutableArray { - (void)populateAllNodesFromNode:(nonnull NSString*)identifier
NSDictionary *nodeDict = [self getNode:identifier]; inArray:(nonnull NSMutableArray<NSDictionary*>*)
mutableArray {
NSDictionary* nodeDict = [self getNode:identifier];
if (nodeDict == nil) { if (nodeDict == nil) {
return; return;
} }
[mutableArray addObject:nodeDict]; [mutableArray addObject:nodeDict];
NSArray *children = nodeDict[@"children"]; NSArray* children = nodeDict[@"children"];
for (NSString *childIdentifier in children) { for (NSString* childIdentifier in children) {
[self populateAllNodesFromNode:childIdentifier inArray:mutableArray]; [self populateAllNodesFromNode:childIdentifier inArray:mutableArray];
} }
} }
- (void)onCallGetAllNodesWithResponder:(nonnull id<FlipperResponder>)responder { - (void)onCallGetAllNodesWithResponder:(nonnull id<FlipperResponder>)responder {
NSMutableArray<NSDictionary*> *allNodes = @[].mutableCopy; NSMutableArray<NSDictionary*>* allNodes = @[].mutableCopy;
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
NSMutableArray *children = [NSMutableArray new]; withDescriptor:(SKNodeDescriptor*)descriptor {
for (NSUInteger i = 0; i < [descriptor childCountForNode: node]; i++) { NSMutableArray* children = [NSMutableArray new];
id childNode = [descriptor childForNode: node atIndex: i]; for (NSUInteger i = 0; i < [descriptor childCountForNode:node]; i++) {
id childNode = [descriptor childForNode:node atIndex:i];
NSString *childIdentifier = [self trackObject: childNode]; NSString* childIdentifier = [self trackObject:childNode];
if (childIdentifier) { if (childIdentifier) {
[children addObject: childIdentifier]; [children addObject:childIdentifier];
} }
} }
return children; return children;
} }
- (void)onCallGetNodes:(NSArray<NSDictionary *> *)nodeIds withResponder:(id<FlipperResponder>)responder { - (void)onCallGetNodes:(NSArray<NSDictionary*>*)nodeIds
NSMutableArray<NSDictionary *> *elements = [NSMutableArray new]; withResponder:(id<FlipperResponder>)responder {
NSMutableArray<NSDictionary*>* elements = [NSMutableArray new];
for (id nodeId in nodeIds) { for (id nodeId in nodeIds) {
const auto node = [self getNode: nodeId]; const auto node = [self getNode:nodeId];
if (node == nil) { if (node == nil) {
continue; continue;
} }
[elements addObject: node]; [elements addObject:node];
} }
[responder success: @{ @"elements": elements }]; [responder success:@{@"elements" : elements}];
} }
- (void)onCallSetData:(NSString *)objectId - (void)onCallSetData:(NSString*)objectId
withPath:(NSArray<NSString *> *)path withPath:(NSArray<NSString*>*)path
toValue:(id<NSObject>)value toValue:(id<NSObject>)value
withConnection:(id<FlipperConnection>)connection { withConnection:(id<FlipperConnection>)connection {
id node = [_trackedObjects objectForKey: objectId]; id node = [_trackedObjects objectForKey:objectId];
if (node == nil) { if (node == nil) {
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;
} }
// Sonar sends nil/NSNull on some values when the text-field // Sonar sends nil/NSNull on some values when the text-field
// is empty, disregard these changes otherwise we'll crash. // is empty, disregard these changes otherwise we'll crash.
if (value == nil || [value isKindOfClass: [NSNull class]]) { if (value == nil || [value isKindOfClass:[NSNull class]]) {
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
const auto alreadyAddedElements = [NSMutableSet<NSString *> new]; withResponder:(id<FlipperResponder>)responder {
SKSearchResultNode *matchTree = [self searchForQuery:(NSString *)[query lowercaseString] fromNode:(id)_rootNode withElementsAlreadyAdded: alreadyAddedElements]; const auto alreadyAddedElements = [NSMutableSet<NSString*> new];
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],
@"query": query @"query" : query
}]; }];
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
[descriptor setHighlighted: NO forNode: lastHighlightedObject]; descriptorForClass:[lastHighlightedObject class]];
[descriptor setHighlighted:NO forNode:lastHighlightedObject];
_lastHighlightedNode = nil; _lastHighlightedNode = nil;
} }
@@ -270,35 +344,37 @@
return; return;
} }
id object = [_trackedObjects objectForKey: objectId]; id object = [_trackedObjects objectForKey:objectId];
if (object == nil) { if (object == nil) {
SKLog(@"tried to setHighlighted for untracked id, objectId: %@", objectId); SKLog(@"tried to setHighlighted for untracked id, objectId: %@", objectId);
return; return;
} }
SKNodeDescriptor *descriptor = [self->_descriptorMapper descriptorForClass: [object class]]; SKNodeDescriptor* descriptor =
[descriptor setHighlighted: YES forNode: object]; [self->_descriptorMapper descriptorForClass:[object class]];
[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 =
[descriptor hitTest: touch forNode: rootNode]; [self->_descriptorMapper descriptorForClass:[rootNode class]];
[descriptor hitTest:touch forNode:rootNode];
}]; }];
} else { } else {
[_tapListener unmount]; [_tapListener unmount];
@@ -306,20 +382,21 @@
} }
- (void)onCallIsSearchActiveWithConnection:(id<FlipperResponder>)responder { - (void)onCallIsSearchActiveWithConnection:(id<FlipperResponder>)responder {
[responder success: @{ @"isSearchActive": @NO }]; [responder success:@{@"isSearchActive" : @NO}];
} }
- (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;
} }
NSString *nodeId = [descriptor identifierForNode: node]; NSString* nodeId = [descriptor identifierForNode:node];
if (![_trackedObjects objectForKey: nodeId]) { if (![_trackedObjects objectForKey:nodeId]) {
return; return;
} }
[descriptor invalidateNode: node]; [descriptor invalidateNode:node];
// Collect invalidate messages before sending in a batch // Collect invalidate messages before sending in a batch
std::lock_guard<std::mutex> lock(invalidObjectsMutex); std::lock_guard<std::mutex> lock(invalidObjectsMutex);
@@ -330,19 +407,24 @@
_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(
[self reportInvalidatedObjects]; dispatch_time(DISPATCH_TIME_NOW, 500 * NSEC_PER_MSEC),
}); dispatch_get_main_queue(),
^{
[self reportInvalidatedObjects];
});
} }
} }
- (void)reportInvalidatedObjects { - (void)reportInvalidatedObjects {
std::lock_guard<std::mutex> lock(invalidObjectsMutex); std::lock_guard<std::mutex> lock(invalidObjectsMutex);
NSMutableArray *nodes = [NSMutableArray new]; NSMutableArray* nodes = [NSMutableArray new];
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,116 +432,125 @@
} }
- (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;
} }
NSString *nodeId = [descriptor identifierForNode: node]; NSString* nodeId = [descriptor identifierForNode:node];
[_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;
} }
NSMutableArray<SKSearchResultNode *> *childTrees = nil; NSMutableArray<SKSearchResultNode*>* childTrees = nil;
BOOL isMatch = [descriptor matchesQuery: query forNode: node]; BOOL isMatch = [descriptor matchesQuery:query forNode:node];
NSString *nodeId = [self trackObject: node]; NSString* nodeId = [self trackObject:node];
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];
} }
[childTrees addObject: childTree]; [childTrees addObject:childTree];
} }
} }
} }
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 =
NSMutableDictionary *newElement = [element mutableCopy]; [element objectForKey:@"children"];
NSMutableDictionary* newElement = [element mutableCopy];
NSMutableArray<NSString *> *childElementsToReturn = [NSMutableArray new]; NSMutableArray<NSString*>* childElementsToReturn = [NSMutableArray new];
for (NSString *child in descriptorChildElements) { for (NSString* child in descriptorChildElements) {
if (![alreadyAdded containsObject: child]) { if (![alreadyAdded containsObject:child]) {
[alreadyAdded addObject: child]; //todo add all at end [alreadyAdded addObject:child]; // todo add all at end
[childElementsToReturn addObject: child]; [childElementsToReturn addObject:child];
} }
} }
[newElement setObject: childElementsToReturn forKey: @"children"]; [newElement setObject:childElementsToReturn forKey:@"children"];
return [[SKSearchResultNode alloc] initWithNode: nodeId return [[SKSearchResultNode alloc] initWithNode:nodeId
asMatch: isMatch asMatch:isMatch
withElement: newElement withElement:newElement
andChildren: childTrees]; andChildren:childTrees];
} }
return nil; return nil;
} }
- (NSDictionary *)getNode:(NSString *)nodeId { - (NSDictionary*)getNode:(NSString*)nodeId {
id<NSObject> node = [_trackedObjects objectForKey: nodeId]; id<NSObject> node = [_trackedObjects objectForKey:nodeId];
if (node == nil) { if (node == nil) {
SKLog(@"node is nil, no tracked node found for nodeId: %@", nodeId); SKLog(@"node is nil, no tracked node found for nodeId: %@", nodeId);
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;
} }
NSMutableArray *attributes = [NSMutableArray new]; NSMutableArray* attributes = [NSMutableArray new];
NSMutableDictionary *data = [NSMutableDictionary new]; NSMutableDictionary* data = [NSMutableDictionary new];
const auto *nodeAttributes = [nodeDescriptor attributesForNode: node]; const auto* nodeAttributes = [nodeDescriptor attributesForNode:node];
for (const SKNamed<NSString *> *namedPair in nodeAttributes) { for (const SKNamed<NSString*>* namedPair in nodeAttributes) {
const auto name = namedPair.name; const auto name = namedPair.name;
if (name) { if (name) {
const NSDictionary *attribute = @{ const NSDictionary* attribute = @{
@"name": name, @"name" : name,
@"value": namedPair.value ?: [NSNull null], @"value" : namedPair.value ?: [NSNull null],
}; };
[attributes addObject: attribute]; [attributes addObject:attribute];
} }
} }
const auto *nodeData = [nodeDescriptor dataForNode: node]; const auto* nodeData = [nodeDescriptor dataForNode:node];
for (const SKNamed<NSDictionary *> *namedPair in nodeData) { for (const SKNamed<NSDictionary*>* namedPair in nodeData) {
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,
@"attributes": attributes, @"attributes" : attributes,
@"data": data, @"data" : data,
@"decoration": [nodeDescriptor decorationForNode: node] ?: @"(unknown)", @"decoration" : [nodeDescriptor decorationForNode:node] ?: @"(unknown)",
}; };
return nodeDic; return nodeDic;
} }
- (NSString *)trackObject:(id)object { - (NSString*)trackObject:(id)object {
const SKNodeDescriptor *descriptor = [_descriptorMapper descriptorForClass: [object class]]; const SKNodeDescriptor* descriptor =
NSString *objectIdentifier = [descriptor identifierForNode: object]; [_descriptorMapper descriptorForClass:[object class]];
NSString* objectIdentifier = [descriptor identifierForNode:object];
if (objectIdentifier == nil) { if (objectIdentifier == nil) {
return nil; return nil;

View File

@@ -13,10 +13,10 @@
- (instancetype)initWithDefaults; - (instancetype)initWithDefaults;
- (SKNodeDescriptor *)descriptorForClass:(Class)cls; - (SKNodeDescriptor*)descriptorForClass:(Class)cls;
- (void)registerDescriptor:(SKNodeDescriptor *)descriptor forClass:(Class)cls; - (void)registerDescriptor:(SKNodeDescriptor*)descriptor forClass:(Class)cls;
- (NSArray<SKNodeDescriptor *> *)allDescriptors; - (NSArray<SKNodeDescriptor*>*)allDescriptors;
@end @end

View File

@@ -15,47 +15,51 @@
#import "SKViewControllerDescriptor.h" #import "SKViewControllerDescriptor.h"
#import "SKViewDescriptor.h" #import "SKViewDescriptor.h"
@implementation SKDescriptorMapper @implementation SKDescriptorMapper {
{ NSMutableDictionary<NSString*, SKNodeDescriptor*>* _descriptors;
NSMutableDictionary<NSString *, SKNodeDescriptor *> *_descriptors;
} }
- (instancetype)initWithDefaults { - (instancetype)initWithDefaults {
if (self = [super init]) { if (self = [super init]) {
_descriptors = [NSMutableDictionary new]; _descriptors = [NSMutableDictionary new];
[self registerDescriptor: [[SKApplicationDescriptor alloc] initWithDescriptorMapper: self] [self registerDescriptor:[[SKApplicationDescriptor alloc]
forClass: [UIApplication class]]; initWithDescriptorMapper:self]
[self registerDescriptor: [[SKViewControllerDescriptor alloc] initWithDescriptorMapper: self] forClass:[UIApplication class]];
forClass: [UIViewController class]]; [self registerDescriptor:[[SKViewControllerDescriptor alloc]
[self registerDescriptor: [[SKScrollViewDescriptor alloc] initWithDescriptorMapper: self] initWithDescriptorMapper:self]
forClass: [UIScrollView class]]; forClass:[UIViewController class]];
[self registerDescriptor: [[SKButtonDescriptor alloc] initWithDescriptorMapper: self] [self registerDescriptor:[[SKScrollViewDescriptor alloc]
forClass: [UIButton class]]; initWithDescriptorMapper:self]
[self registerDescriptor: [[SKViewDescriptor alloc] initWithDescriptorMapper: self] forClass:[UIScrollView class]];
forClass: [UIView class]]; [self registerDescriptor:[[SKButtonDescriptor alloc]
initWithDescriptorMapper:self]
forClass:[UIButton class]];
[self registerDescriptor:[[SKViewDescriptor alloc]
initWithDescriptorMapper:self]
forClass:[UIView class]];
} }
return self; return self;
} }
- (SKNodeDescriptor *)descriptorForClass:(Class)cls { - (SKNodeDescriptor*)descriptorForClass:(Class)cls {
SKNodeDescriptor *classDescriptor = nil; SKNodeDescriptor* classDescriptor = nil;
while (classDescriptor == nil && cls != nil) { while (classDescriptor == nil && cls != nil) {
classDescriptor = [_descriptors objectForKey: NSStringFromClass(cls)]; classDescriptor = [_descriptors objectForKey:NSStringFromClass(cls)];
cls = [cls superclass]; cls = [cls superclass];
} }
return classDescriptor; return classDescriptor;
} }
- (void)registerDescriptor:(SKNodeDescriptor *)descriptor forClass:(Class)cls { - (void)registerDescriptor:(SKNodeDescriptor*)descriptor forClass:(Class)cls {
NSString *className = NSStringFromClass(cls); NSString* className = NSStringFromClass(cls);
_descriptors[className] = descriptor; _descriptors[className] = descriptor;
} }
- (NSArray<SKNodeDescriptor *> *)allDescriptors { - (NSArray<SKNodeDescriptor*>*)allDescriptors {
return [_descriptors allValues]; return [_descriptors allValues];
} }

View File

@@ -21,6 +21,6 @@
+ (void)enableInvalidations; + (void)enableInvalidations;
@property (nonatomic, weak) id<SKInvalidationDelegate> delegate; @property(nonatomic, weak) id<SKInvalidationDelegate> delegate;
@end @end

View File

@@ -10,13 +10,13 @@
#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
+ (instancetype)sharedInstance { + (instancetype)sharedInstance {
static SKInvalidation *sInstance = nil; static SKInvalidation* sInstance = nil;
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{
@@ -32,24 +32,28 @@
[UIView enableInvalidation]; [UIView enableInvalidation];
[UICollectionView enableInvalidations]; [UICollectionView enableInvalidations];
[[NSNotificationCenter defaultCenter] addObserver:self [[NSNotificationCenter defaultCenter]
selector:@selector(windowDidBecomeVisible:) addObserver:self
name:UIWindowDidBecomeVisibleNotification selector:@selector(windowDidBecomeVisible:)
object:nil]; name:UIWindowDidBecomeVisibleNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self [[NSNotificationCenter defaultCenter]
selector:@selector(windowDidBecomeHidden:) addObserver:self
name:UIWindowDidBecomeHiddenNotification selector:@selector(windowDidBecomeHidden:)
object:nil]; name:UIWindowDidBecomeHiddenNotification
object:nil];
}); });
} }
+ (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

@@ -9,9 +9,9 @@
@interface SKNamed<__covariant T> : NSObject @interface SKNamed<__covariant T> : NSObject
+ (instancetype)newWithName:(NSString *)name withValue:(T)value; + (instancetype)newWithName:(NSString*)name withValue:(T)value;
@property (nonatomic, readonly) NSString *name; @property(nonatomic, readonly) NSString* name;
@property (nonatomic, readonly) T value; @property(nonatomic, readonly) T value;
@end @end

View File

@@ -11,11 +11,11 @@
@implementation SKNamed @implementation SKNamed
+ (instancetype)newWithName:(NSString *)name withValue:(id)value { + (instancetype)newWithName:(NSString*)name withValue:(id)value {
return [[SKNamed alloc] initWithName: name withValue: value]; return [[SKNamed alloc] initWithName:name withValue:value];
} }
- (instancetype)initWithName:(NSString *)name withValue:(id)value { - (instancetype)initWithName:(NSString*)name withValue:(id)value {
if (self = [super init]) { if (self = [super init]) {
_name = name; _name = name;
_value = value; _value = value;
@@ -24,7 +24,7 @@
return self; return self;
} }
- (NSString *)description { - (NSString*)description {
return [NSString stringWithFormat:@"%@: %@", _name, _value]; return [NSString stringWithFormat:@"%@: %@", _name, _value];
} }

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,34 +27,35 @@ 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;
/** /**
Gets the node-descriptor registered for a specific class. Gets the node-descriptor registered for a specific class.
*/ */
- (SKNodeDescriptor *)descriptorForClass:(Class)cls; - (SKNodeDescriptor*)descriptorForClass:(Class)cls;
/** /**
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;
/** /**
The number of children this node exposes in the layout hierarchy. The number of children this node exposes in the layout hierarchy.
@@ -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;
@@ -98,7 +100,7 @@ typedef void (^SKNodeUpdateData)(id value);
one of the children of the node, or finish the hit testing on this one of the children of the node, or finish the hit testing on this
node. node.
*/ */
- (void)hitTest:(SKTouch *)point forNode:(T)node; - (void)hitTest:(SKTouch*)point forNode:(T)node;
/** /**
Invalidate a specific node. This is called once a node is removed or added Invalidate a specific node. This is called once a node is removed or added
@@ -110,12 +112,12 @@ typedef void (^SKNodeUpdateData)(id value);
The decoration for this node. Valid values are defined in the Sonar The decoration for this node. Valid values are defined in the Sonar
applictation. applictation.
*/ */
- (NSString *)decorationForNode:(T)node; - (NSString*)decorationForNode:(T)node;
/** /**
Whether the node matches the given query. Whether the node matches the given query.
Used for layout search. Used for layout search.
*/ */
- (BOOL)matchesQuery:(NSString *)query forNode:(T)node; - (BOOL)matchesQuery:(NSString*)query forNode:(T)node;
@end @end

View File

@@ -10,87 +10,89 @@
#import "SKNodeDescriptor.h" #import "SKNodeDescriptor.h"
#import <FlipperKitLayoutTextSearchable/FKTextSearchable.h> #import <FlipperKitLayoutTextSearchable/FKTextSearchable.h>
@implementation SKNodeDescriptor @implementation SKNodeDescriptor {
{ SKDescriptorMapper* _mapper;
SKDescriptorMapper *_mapper;
} }
- (void)setUp { - (void)setUp {
} }
- (instancetype)initWithDescriptorMapper:(SKDescriptorMapper *)mapper { - (instancetype)initWithDescriptorMapper:(SKDescriptorMapper*)mapper {
if (self = [super init]) { if (self = [super init]) {
_mapper = mapper; _mapper = mapper;
} }
return self; return self;
} }
- (SKNodeDescriptor *)descriptorForClass:(Class)cls { - (SKNodeDescriptor*)descriptorForClass:(Class)cls {
return [_mapper descriptorForClass: cls]; return [_mapper descriptorForClass:cls];
} }
- (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];
} }
- (NSString *)nameForNode:(id)node { - (NSString*)nameForNode:(id)node {
return NSStringFromClass([node class]); return NSStringFromClass([node class]);
} }
- (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 {
return @{}; return @{};
} }
- (NSArray<SKNamed<NSDictionary *> *> *)dataForNode:(id)node { - (NSArray<SKNamed<NSDictionary*>*>*)dataForNode:(id)node {
return @[]; return @[];
} }
- (NSArray<SKNamed<NSString *> *> *)attributesForNode:(id)node { - (NSArray<SKNamed<NSString*>*>*)attributesForNode:(id)node {
return @[]; return @[];
} }
- (void)setHighlighted:(BOOL)highlighted forNode:(id)node { - (void)setHighlighted:(BOOL)highlighted forNode:(id)node {
} }
- (void)hitTest:(SKTouch *)point forNode:(id)node { - (void)hitTest:(SKTouch*)point forNode:(id)node {
} }
- (void)invalidateNode:(id)node { - (void)invalidateNode:(id)node {
} }
- (NSString *)decorationForNode:(id)node { - (NSString*)decorationForNode:(id)node {
return @""; return @"";
} }
- (BOOL)matchesQuery:(NSString *)query forNode:(id)node { - (BOOL)matchesQuery:(NSString*)query forNode:(id)node {
NSString *name = [self nameForNode: node]; NSString* name = [self nameForNode:node];
NSString *text = nil; NSString* text = nil;
if ([node conformsToProtocol:@protocol(FKTextSearchable)]) { if ([node conformsToProtocol:@protocol(FKTextSearchable)]) {
text = [node searchableText]; text = [node searchableText];
} }
return [self string:name contains:query] || return [self string:name contains:query] ||
[self string:[self identifierForNode: node] contains: query] || [self string:[self identifierForNode:node] contains:query] ||
[self string:text contains:query]; [self string:text contains:query];
} }
- (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

@@ -11,12 +11,12 @@
+ (instancetype)fromSonarValue:(id)sonarValue; + (instancetype)fromSonarValue:(id)sonarValue;
- (NSDictionary<NSString *, id<NSObject>> *)sonarValue; - (NSDictionary<NSString*, id<NSObject>>*)sonarValue;
@end @end
class SKObject { class SKObject {
public: public:
SKObject(CGRect rect); SKObject(CGRect rect);
SKObject(CGSize size); SKObject(CGSize size);
SKObject(CGPoint point); SKObject(CGPoint point);
@@ -25,28 +25,30 @@ public:
SKObject(id<SKSonarValueCoder> value); SKObject(id<SKSonarValueCoder> value);
SKObject(id value); SKObject(id value);
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;
}; };
class SKMutableObject : public SKObject { class SKMutableObject : public SKObject {
public: public:
SKMutableObject(CGRect rect) : SKObject(rect) { } SKMutableObject(CGRect rect) : SKObject(rect) {}
SKMutableObject(CGSize size) : SKObject(size) { }; SKMutableObject(CGSize size) : SKObject(size){};
SKMutableObject(CGPoint point) : SKObject(point) { }; SKMutableObject(CGPoint point) : SKObject(point){};
SKMutableObject(UIEdgeInsets insets) : SKObject(insets) { }; SKMutableObject(UIEdgeInsets insets) : SKObject(insets){};
SKMutableObject(CGAffineTransform transform) : SKObject(transform) { }; SKMutableObject(CGAffineTransform transform) : SKObject(transform){};
SKMutableObject(id<SKSonarValueCoder> value) : SKObject(value) { }; SKMutableObject(id<SKSonarValueCoder> value) : SKObject(value){};
SKMutableObject(id value) : SKObject(value) { }; SKMutableObject(id value) : SKObject(value){};
operator id<NSObject> () { operator id<NSObject>() {
convertToMutable(); convertToMutable();
return _actual; return _actual;
} }
protected:
protected:
BOOL _convertedToMutable = NO; BOOL _convertedToMutable = NO;
void convertToMutable(); void convertToMutable();
}; };

View File

@@ -10,86 +10,80 @@
#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) {
_actual = @{ _actual = @{
@"top": @(insets.top), @"top" : @(insets.top),
@"bottom": @(insets.bottom), @"bottom" : @(insets.bottom),
@"left": @(insets.left), @"left" : @(insets.left),
@"right": @(insets.right), @"right" : @(insets.right),
}; };
} }
SKObject::SKObject(CGAffineTransform transform) { SKObject::SKObject(CGAffineTransform transform) {
_actual = @{ _actual = @{
@"a": @(transform.a), @"a" : @(transform.a),
@"b": @(transform.b), @"b" : @(transform.b),
@"c": @(transform.c), @"c" : @(transform.c),
@"d": @(transform.d), @"d" : @(transform.d),
@"tx": @(transform.tx), @"tx" : @(transform.tx),
@"ty": @(transform.ty), @"ty" : @(transform.ty),
}; };
} }
SKObject::SKObject(id<SKSonarValueCoder> value) : _actual([value sonarValue]) { } SKObject::SKObject(id<SKSonarValueCoder> value) : _actual([value sonarValue]) {}
SKObject::SKObject(id value) : _actual(value) { } SKObject::SKObject(id value) : _actual(value) {}
static NSString *_objectType(id<NSObject> object) { static NSString* _objectType(id<NSObject> object) {
if ([object isKindOfClass: [NSDictionary class]]) { if ([object isKindOfClass:[NSDictionary class]]) {
return (NSString *)((NSDictionary *)object)[@"__type__"]; return (NSString*)((NSDictionary*)object)[@"__type__"];
} }
return nil; return nil;
} }
static id<NSObject> _objectValue(id<NSObject> object) { static id<NSObject> _objectValue(id<NSObject> object) {
if ([object isKindOfClass: [NSDictionary class]]) { if ([object isKindOfClass:[NSDictionary class]]) {
return ((NSDictionary *)object)[@"value"]; return ((NSDictionary*)object)[@"value"];
} }
return object; return object;
} }
static NSDictionary<NSString *, id<NSObject>> *_SKValue(id<NSObject> object, BOOL isMutable) { static NSDictionary<NSString*, id<NSObject>>* _SKValue(
NSString *type = _objectType(object); id<NSObject> object,
BOOL isMutable) {
NSString* type = _objectType(object);
id<NSObject> value = _objectValue(object); id<NSObject> value = _objectValue(object);
return @{ return @{
@"__type__": (type != nil ? type : @"auto"), @"__type__" : (type != nil ? type : @"auto"),
@"__mutable__": @(isMutable), @"__mutable__" : @(isMutable),
@"value": (value != nil ? value : [NSNull null]), @"value" : (value != nil ? value : [NSNull null]),
}; };
} }
static NSDictionary *_SKMutable(const NSDictionary<NSString *, id<NSObject>> *skObject) { static NSDictionary* _SKMutable(
NSMutableDictionary *mutableObject = [NSMutableDictionary new]; const NSDictionary<NSString*, id<NSObject>>* skObject) {
for (NSString *key: skObject) { NSMutableDictionary* mutableObject = [NSMutableDictionary new];
for (NSString* key : skObject) {
id<NSObject> value = skObject[key]; id<NSObject> value = skObject[key];
if (_objectType(value) != nil) { if (_objectType(value) != nil) {
mutableObject[key] = _SKValue(value, YES); mutableObject[key] = _SKValue(value, YES);
} else if ([value isKindOfClass: [NSDictionary class]]) { } else if ([value isKindOfClass:[NSDictionary class]]) {
auto objectValue = (NSDictionary<NSString *, id<NSObject>>*) value; auto objectValue = (NSDictionary<NSString*, id<NSObject>>*)value;
mutableObject[key] = _SKMutable(objectValue); mutableObject[key] = _SKMutable(objectValue);
} else { } else {
mutableObject[key] = _SKValue(value, YES); mutableObject[key] = _SKValue(value, YES);
@@ -104,8 +98,9 @@ void SKMutableObject::convertToMutable() {
return; return;
} }
if (_objectType(_actual) == nil && [_actual isKindOfClass: [NSDictionary class]]) { if (_objectType(_actual) == nil &&
auto object = (const NSDictionary<NSString *, id<NSObject>> *)_actual; [_actual isKindOfClass:[NSDictionary class]]) {
auto object = (const NSDictionary<NSString*, id<NSObject>>*)_actual;
_actual = _SKMutable(object); _actual = _SKMutable(object);
} else { } else {
_actual = _SKValue(_actual, YES); _actual = _SKValue(_actual, YES);

View File

@@ -12,14 +12,14 @@
@interface SKSearchResultNode : NSObject @interface SKSearchResultNode : NSObject
@property (nonatomic, copy, readonly) NSString *nodeId; @property(nonatomic, copy, readonly) NSString* nodeId;
- (instancetype)initWithNode:(NSString *)nodeId - (instancetype)initWithNode:(NSString*)nodeId
asMatch:(BOOL)isMatch asMatch:(BOOL)isMatch
withElement:(NSDictionary *)element withElement:(NSDictionary*)element
andChildren:(NSArray<SKSearchResultNode *> *)children; andChildren:(NSArray<SKSearchResultNode*>*)children;
- (NSDictionary *)toNSDictionary; - (NSDictionary*)toNSDictionary;
@end @end
#endif /* SKSearchResultNode_h */ #endif /* SKSearchResultNode_h */

View File

@@ -8,48 +8,48 @@
#import "SKSearchResultNode.h" #import "SKSearchResultNode.h"
@implementation SKSearchResultNode { @implementation SKSearchResultNode {
NSString *_nodeId; NSString* _nodeId;
BOOL _isMatch; BOOL _isMatch;
NSDictionary *_element; NSDictionary* _element;
NSArray<SKSearchResultNode *> *_children; NSArray<SKSearchResultNode*>* _children;
} }
- (instancetype)initWithNode:(NSString *)nodeId - (instancetype)initWithNode:(NSString*)nodeId
asMatch:(BOOL)isMatch asMatch:(BOOL)isMatch
withElement:(NSDictionary *)element withElement:(NSDictionary*)element
andChildren:(NSArray<SKSearchResultNode *> *)children { andChildren:(NSArray<SKSearchResultNode*>*)children {
self = [super init]; self = [super init];
if (self) { if (self) {
_nodeId = nodeId; _nodeId = nodeId;
_isMatch = isMatch; _isMatch = isMatch;
_element = element; _element = element;
_children = children; _children = children;
} }
return self; return self;
} }
- (NSDictionary *)toNSDictionary { - (NSDictionary*)toNSDictionary {
if (_element == nil) { if (_element == nil) {
return nil; return nil;
} }
NSMutableArray<NSDictionary *> *childArray; NSMutableArray<NSDictionary*>* childArray;
if (_children) { if (_children) {
childArray = [NSMutableArray new]; childArray = [NSMutableArray new];
for (SKSearchResultNode *child in _children) { for (SKSearchResultNode* child in _children) {
NSDictionary *childDict = [child toNSDictionary]; NSDictionary* childDict = [child toNSDictionary];
if (childDict) { if (childDict) {
[childArray addObject:childDict]; [childArray addObject:childDict];
} }
} }
} else { } else {
childArray = nil; childArray = nil;
} }
return @{ return @{
@"id": _nodeId, @"id" : _nodeId,
@"isMatch": @(_isMatch), @"isMatch" : @(_isMatch),
@"element": _element, @"element" : _element,
@"children": childArray ?: [NSNull null] @"children" : childArray ?: [NSNull null]
}; };
} }
@end @end

View File

@@ -11,7 +11,7 @@ typedef void (^SKTapReceiver)(CGPoint touchPoint);
@protocol SKTapListener @protocol SKTapListener
@property (nonatomic, readonly) BOOL isMounted; @property(nonatomic, readonly) BOOL isMounted;
- (void)mountWithFrame:(CGRect)frame; - (void)mountWithFrame:(CGRect)frame;

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,12 +13,11 @@
#import <FlipperKitHighlightOverlay/SKHighlightOverlay.h> #import <FlipperKitHighlightOverlay/SKHighlightOverlay.h>
@implementation SKTapListenerImpl @implementation SKTapListenerImpl {
{ NSMutableArray<SKTapReceiver>* _receiversWaitingForInput;
NSMutableArray<SKTapReceiver> *_receiversWaitingForInput; UITapGestureRecognizer* _gestureRecognizer;
UITapGestureRecognizer *_gestureRecognizer;
SKHiddenWindow *_overlayWindow; SKHiddenWindow* _overlayWindow;
} }
@synthesize isMounted = _isMounted; @synthesize isMounted = _isMounted;
@@ -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;
@@ -37,7 +37,7 @@
_overlayWindow.windowLevel = UIWindowLevelAlert; _overlayWindow.windowLevel = UIWindowLevelAlert;
_overlayWindow.backgroundColor = [SKHighlightOverlay overlayColor]; _overlayWindow.backgroundColor = [SKHighlightOverlay overlayColor];
[_overlayWindow addGestureRecognizer: _gestureRecognizer]; [_overlayWindow addGestureRecognizer:_gestureRecognizer];
} }
return self; return self;
@@ -48,7 +48,7 @@
return; return;
} }
[_overlayWindow setFrame: frame]; [_overlayWindow setFrame:frame];
[_overlayWindow makeKeyAndVisible]; [_overlayWindow makeKeyAndVisible];
_overlayWindow.hidden = NO; _overlayWindow.hidden = NO;
@@ -68,15 +68,16 @@
} }
- (void)listenForTapWithBlock:(SKTapReceiver)receiver { - (void)listenForTapWithBlock:(SKTapReceiver)receiver {
[_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;
} }
CGPoint touchPoint = [touch locationInView: _overlayWindow]; CGPoint touchPoint = [touch locationInView:_overlayWindow];
for (SKTapReceiver recv in _receiversWaitingForInput) { for (SKTapReceiver recv in _receiversWaitingForInput) {
recv(touchPoint); recv(touchPoint);

View File

@@ -9,17 +9,17 @@
#import "SKDescriptorMapper.h" #import "SKDescriptorMapper.h"
typedef void (^SKTouchFinishDelegate)(NSArray<NSString *> *path); typedef void (^SKTouchFinishDelegate)(NSArray<NSString*>* path);
@interface SKTouch : NSObject @interface SKTouch : NSObject
- (instancetype)initWithTouchPoint:(CGPoint)touchPoint - (instancetype)initWithTouchPoint:(CGPoint)touchPoint
withRootNode:(id<NSObject>)node withRootNode:(id<NSObject>)node
withDescriptorMapper:(SKDescriptorMapper *)mapper withDescriptorMapper:(SKDescriptorMapper*)mapper
finishWithBlock:(SKTouchFinishDelegate)d; finishWithBlock:(SKTouchFinishDelegate)d;
- (void)continueWithChildIndex:(NSUInteger)childIndex - (void)continueWithChildIndex:(NSUInteger)childIndex
withOffset:(CGPoint)offset; withOffset:(CGPoint)offset;
- (void)finish; - (void)finish;

View File

@@ -10,21 +10,20 @@
#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;
CGPoint _currentTouchPoint; CGPoint _currentTouchPoint;
id<NSObject> _currentNode; id<NSObject> _currentNode;
SKDescriptorMapper *_descriptorMapper; SKDescriptorMapper* _descriptorMapper;
} }
- (instancetype)initWithTouchPoint:(CGPoint)touchPoint - (instancetype)initWithTouchPoint:(CGPoint)touchPoint
withRootNode:(id<NSObject>)node withRootNode:(id<NSObject>)node
withDescriptorMapper:(SKDescriptorMapper *)mapper withDescriptorMapper:(SKDescriptorMapper*)mapper
finishWithBlock:(SKTouchFinishDelegate)finishBlock { finishWithBlock:(SKTouchFinishDelegate)finishBlock {
if (self = [super init]) { if (self = [super init]) {
_onFinish = finishBlock; _onFinish = finishBlock;
_currentTouchPoint = touchPoint; _currentTouchPoint = touchPoint;
@@ -36,17 +35,19 @@
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 =
_currentNode = [descriptor childForNode: _currentNode atIndex: childIndex]; [_descriptorMapper descriptorForClass:[_currentNode class]];
_currentNode = [descriptor childForNode:_currentNode atIndex:childIndex];
descriptor = [_descriptorMapper descriptorForClass: [_currentNode class]]; descriptor = [_descriptorMapper descriptorForClass:[_currentNode class]];
[_path addObject: [descriptor identifierForNode: _currentNode]]; [_path addObject:[descriptor identifierForNode:_currentNode]];
[descriptor hitTest: self forNode: _currentNode]; [descriptor hitTest:self forNode:_currentNode];
} }
- (void)finish { - (void)finish {

View File

@@ -18,16 +18,20 @@ 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];
}); });
return [self swizzle_cellForItemAtIndexPath: indexPath]; return [self swizzle_cellForItemAtIndexPath:indexPath];
} }
@end @end

View File

@@ -12,6 +12,6 @@
#import "SKObject.h" #import "SKObject.h"
FB_LINK_REQUIRE_CATEGORY(UIColor_SonarValueCoder) FB_LINK_REQUIRE_CATEGORY(UIColor_SonarValueCoder)
@interface UIColor (SonarValueCoder) <SKSonarValueCoder> @interface UIColor (SonarValueCoder)<SKSonarValueCoder>
@end @end

View File

@@ -12,7 +12,7 @@
FB_LINKABLE(UIColor_SonarValueCoder) FB_LINKABLE(UIColor_SonarValueCoder)
@implementation UIColor (SonarValueCoder) @implementation UIColor (SonarValueCoder)
+ (instancetype)fromSonarValue:(NSNumber *)sonarValue { + (instancetype)fromSonarValue:(NSNumber*)sonarValue {
NSUInteger intColor = [sonarValue integerValue]; NSUInteger intColor = [sonarValue integerValue];
CGFloat r, g, b, a; CGFloat r, g, b, a;
@@ -22,10 +22,10 @@ FB_LINKABLE(UIColor_SonarValueCoder)
r = CGFloat((intColor >> 16) & 0xFF) / 255; r = CGFloat((intColor >> 16) & 0xFF) / 255;
a = CGFloat((intColor >> 24) & 0xFF) / 255; a = CGFloat((intColor >> 24) & 0xFF) / 255;
return [[UIColor alloc] initWithRed: r green: g blue: b alpha: a]; return [[UIColor alloc] initWithRed:r green:g blue:b alpha:a];
} }
- (NSDictionary<NSString *, id<NSObject>> *)sonarValue { - (NSDictionary<NSString*, id<NSObject>>*)sonarValue {
CGColorSpaceRef colorSpace = CGColorGetColorSpace([self CGColor]); CGColorSpaceRef colorSpace = CGColorGetColorSpace([self CGColor]);
CGColorSpaceModel colorSpaceModel = CGColorSpaceGetModel(colorSpace); CGColorSpaceModel colorSpaceModel = CGColorSpaceGetModel(colorSpace);
@@ -35,7 +35,7 @@ FB_LINKABLE(UIColor_SonarValueCoder)
case kCGColorSpaceModelUnknown: case kCGColorSpaceModelUnknown:
case kCGColorSpaceModelRGB: { case kCGColorSpaceModelRGB: {
CGFloat r, g, b, a; CGFloat r, g, b, a;
[self getRed: &r green: &g blue: &b alpha: &a]; [self getRed:&r green:&g blue:&b alpha:&a];
red = (NSUInteger)(r * 255) & 0xFF; red = (NSUInteger)(r * 255) & 0xFF;
green = (NSUInteger)(g * 255) & 0xFF; green = (NSUInteger)(g * 255) & 0xFF;
@@ -45,7 +45,7 @@ FB_LINKABLE(UIColor_SonarValueCoder)
case kCGColorSpaceModelMonochrome: { case kCGColorSpaceModelMonochrome: {
CGFloat a, w; CGFloat a, w;
[self getWhite: &w alpha: &a]; [self getWhite:&w alpha:&a];
red = green = blue = (NSUInteger)(w * 255) & 0xFF; red = green = blue = (NSUInteger)(w * 255) & 0xFF;
alpha = (NSUInteger)(a * 255) & 0xFF; alpha = (NSUInteger)(a * 255) & 0xFF;
@@ -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,34 +20,42 @@ 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];
} }
} }
- (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];
} }
[self swizzle_removeFromSuperview]; [self swizzle_removeFromSuperview];

View File

@@ -9,6 +9,6 @@
#import "SKNodeDescriptor.h" #import "SKNodeDescriptor.h"
@interface SKApplicationDescriptor : SKNodeDescriptor<UIApplication *> @interface SKApplicationDescriptor : SKNodeDescriptor<UIApplication*>
@end @end

View File

@@ -9,38 +9,40 @@
#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
- (NSString *)identifierForNode:(UIApplication *)node { - (NSString*)identifierForNode:(UIApplication*)node {
return [NSString stringWithFormat: @"%p", node]; return [NSString stringWithFormat:@"%p", node];
} }
- (NSUInteger)childCountForNode:(UIApplication *)node { - (NSUInteger)childCountForNode:(UIApplication*)node {
return [[self visibleChildrenForNode: node] count]; return [[self visibleChildrenForNode:node] count];
} }
- (id)childForNode:(UIApplication *)node atIndex:(NSUInteger)index { - (id)childForNode:(UIApplication*)node atIndex:(NSUInteger)index {
return [self visibleChildrenForNode: node][index]; return [self visibleChildrenForNode:node][index];
} }
- (void)setHighlighted:(BOOL)highlighted forNode:(UIApplication *)node { - (void)setHighlighted:(BOOL)highlighted forNode:(UIApplication*)node {
SKNodeDescriptor *windowDescriptor = [self descriptorForClass: [UIWindow class]]; SKNodeDescriptor* windowDescriptor =
[windowDescriptor setHighlighted: highlighted forNode: [node keyWindow]]; [self descriptorForClass:[UIWindow class]];
[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;
UIWindow *child = [self childForNode: node atIndex: index]; index--) {
UIWindow* child = [self childForNode:node atIndex:index];
if (child.isHidden || child.alpha <= 0) { if (child.isHidden || child.alpha <= 0) {
continue; continue;
} }
if ([touch containedIn: child.frame]) { if ([touch containedIn:child.frame]) {
[touch continueWithChildIndex: index withOffset: child.frame.origin]; [touch continueWithChildIndex:index withOffset:child.frame.origin];
return; return;
} }
} }
@@ -48,16 +50,17 @@
[touch finish]; [touch finish];
} }
- (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];
} }
return children; return children;
} }

View File

@@ -11,6 +11,6 @@
@class UIButton; @class UIButton;
@interface SKButtonDescriptor : SKNodeDescriptor<UIButton *> @interface SKButtonDescriptor : SKNodeDescriptor<UIButton*>
@end @end

View File

@@ -15,44 +15,48 @@
@implementation SKButtonDescriptor @implementation SKButtonDescriptor
- (NSString *)identifierForNode:(UIButton *)node { - (NSString*)identifierForNode:(UIButton*)node {
return [NSString stringWithFormat: @"%p", node]; return [NSString stringWithFormat:@"%p", node];
} }
- (NSUInteger)childCountForNode:(UIButton *)node { - (NSUInteger)childCountForNode:(UIButton*)node {
return 0; return 0;
} }
- (id)childForNode:(UIButton *)node atIndex:(NSUInteger)index { - (id)childForNode:(UIButton*)node atIndex:(NSUInteger)index {
return nil; return nil;
} }
- (NSArray<SKNamed<NSDictionary *> *> *)dataForNode:(UIButton *)node { - (NSArray<SKNamed<NSDictionary*>*>*)dataForNode:(UIButton*)node {
SKNodeDescriptor *viewDescriptor = [self descriptorForClass: [UIView class]]; SKNodeDescriptor* viewDescriptor = [self descriptorForClass:[UIView class]];
auto *viewData = [viewDescriptor dataForNode: node]; auto* viewData = [viewDescriptor dataForNode:node];
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 =
[node setTitle: newValue forState: node.state]; @{@"UIButton.titleLabel" : ^(NSString* newValue){
}, [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,29 +66,30 @@
@"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];
NSMutableDictionary *mutations = [NSMutableDictionary new]; NSMutableDictionary* mutations = [NSMutableDictionary new];
[mutations addEntriesFromDictionary: buttonMutations]; [mutations addEntriesFromDictionary:buttonMutations];
[mutations addEntriesFromDictionary: viewMutations]; [mutations addEntriesFromDictionary:viewMutations];
return mutations; return mutations;
} }
- (NSArray<SKNamed<NSString *> *> *)attributesForNode:(UIScrollView *)node { - (NSArray<SKNamed<NSString*>*>*)attributesForNode:(UIScrollView*)node {
SKNodeDescriptor *descriptor = [self descriptorForClass: [UIView class]]; SKNodeDescriptor* descriptor = [self descriptorForClass:[UIView class]];
return [descriptor attributesForNode: node]; return [descriptor attributesForNode:node];
} }
- (void)setHighlighted:(BOOL)highlighted forNode:(UIButton *)node { - (void)setHighlighted:(BOOL)highlighted forNode:(UIButton*)node {
SKNodeDescriptor *viewDescriptor = [self descriptorForClass: [UIView class]]; SKNodeDescriptor* viewDescriptor = [self descriptorForClass:[UIView class]];
[viewDescriptor setHighlighted: highlighted forNode: node]; [viewDescriptor setHighlighted:highlighted forNode:node];
} }
- (void)hitTest:(SKTouch *)touch forNode:(UIButton *)node { - (void)hitTest:(SKTouch*)touch forNode:(UIButton*)node {
[touch finish]; [touch finish];
} }

View File

@@ -9,6 +9,6 @@
#import "SKNodeDescriptor.h" #import "SKNodeDescriptor.h"
@interface SKScrollViewDescriptor : SKNodeDescriptor<UIScrollView *> @interface SKScrollViewDescriptor : SKNodeDescriptor<UIScrollView*>
@end @end

View File

@@ -13,55 +13,56 @@
@implementation SKScrollViewDescriptor @implementation SKScrollViewDescriptor
- (NSString *)identifierForNode:(UIScrollView *)node { - (NSString*)identifierForNode:(UIScrollView*)node {
SKNodeDescriptor *descriptor = [self descriptorForClass: [UIView class]]; SKNodeDescriptor* descriptor = [self descriptorForClass:[UIView class]];
return [descriptor identifierForNode: node]; return [descriptor identifierForNode:node];
} }
- (NSUInteger)childCountForNode:(UIScrollView *)node { - (NSUInteger)childCountForNode:(UIScrollView*)node {
SKNodeDescriptor *descriptor = [self descriptorForClass: [UIView class]]; SKNodeDescriptor* descriptor = [self descriptorForClass:[UIView class]];
return [descriptor childCountForNode: node]; return [descriptor childCountForNode:node];
} }
- (id)childForNode:(UIScrollView *)node atIndex:(NSUInteger)index { - (id)childForNode:(UIScrollView*)node atIndex:(NSUInteger)index {
SKNodeDescriptor *descriptor = [self descriptorForClass: [UIView class]]; SKNodeDescriptor* descriptor = [self descriptorForClass:[UIView class]];
return [descriptor childForNode: node atIndex: index]; return [descriptor childForNode:node atIndex:index];
} }
- (id)dataForNode:(UIScrollView *)node { - (id)dataForNode:(UIScrollView*)node {
SKNodeDescriptor *descriptor = [self descriptorForClass: [UIView class]]; SKNodeDescriptor* descriptor = [self descriptorForClass:[UIView class]];
return [descriptor dataForNode:node]; return [descriptor dataForNode:node];
} }
- (id)dataMutationsForNode:(UIScrollView *)node { - (id)dataMutationsForNode:(UIScrollView*)node {
SKNodeDescriptor *descriptor = [self descriptorForClass: [UIView class]]; SKNodeDescriptor* descriptor = [self descriptorForClass:[UIView class]];
return [descriptor dataMutationsForNode:node]; return [descriptor dataMutationsForNode:node];
} }
- (NSArray<SKNamed<NSString *> *> *)attributesForNode:(UIScrollView *)node { - (NSArray<SKNamed<NSString*>*>*)attributesForNode:(UIScrollView*)node {
SKNodeDescriptor *descriptor = [self descriptorForClass: [UIView class]]; SKNodeDescriptor* descriptor = [self descriptorForClass:[UIView class]];
return [descriptor attributesForNode: node]; return [descriptor attributesForNode:node];
} }
- (void)setHighlighted:(BOOL)highlighted forNode:(UIScrollView *)node { - (void)setHighlighted:(BOOL)highlighted forNode:(UIScrollView*)node {
SKNodeDescriptor *descriptor = [self descriptorForClass: [UIView class]]; SKNodeDescriptor* descriptor = [self descriptorForClass:[UIView class]];
[descriptor setHighlighted: highlighted forNode: node]; [descriptor setHighlighted:highlighted forNode:node];
} }
- (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;
id<NSObject> childNode = [self childForNode: node atIndex: index]; index--) {
id<NSObject> childNode = [self childForNode:node atIndex:index];
CGRect frame; CGRect frame;
if ([childNode isKindOfClass: [UIViewController class]]) { if ([childNode isKindOfClass:[UIViewController class]]) {
UIViewController *child = (UIViewController *)childNode; UIViewController* child = (UIViewController*)childNode;
if (child.view.isHidden) { if (child.view.isHidden) {
continue; continue;
} }
frame = child.view.frame; frame = child.view.frame;
} else { } else {
UIView *child = (UIView *)childNode; UIView* child = (UIView*)childNode;
if (child.isHidden) { if (child.isHidden) {
continue; continue;
} }
@@ -72,8 +73,8 @@
frame.origin.x -= node.contentOffset.x; frame.origin.x -= node.contentOffset.x;
frame.origin.y -= node.contentOffset.y; frame.origin.y -= node.contentOffset.y;
if ([touch containedIn: frame]) { if ([touch containedIn:frame]) {
[touch continueWithChildIndex: index withOffset: frame.origin]; [touch continueWithChildIndex:index withOffset:frame.origin];
return; return;
} }
} }

View File

@@ -9,6 +9,6 @@
#import "SKNodeDescriptor.h" #import "SKNodeDescriptor.h"
@interface SKViewControllerDescriptor : SKNodeDescriptor<UIViewController *> @interface SKViewControllerDescriptor : SKNodeDescriptor<UIViewController*>
@end @end

View File

@@ -13,38 +13,35 @@
@implementation SKViewControllerDescriptor @implementation SKViewControllerDescriptor
- (NSString *)identifierForNode:(UIViewController *)node { - (NSString*)identifierForNode:(UIViewController*)node {
return [NSString stringWithFormat: @"%p", node]; return [NSString stringWithFormat:@"%p", node];
} }
- (NSUInteger)childCountForNode:(UIViewController *)node { - (NSUInteger)childCountForNode:(UIViewController*)node {
return 1; return 1;
} }
- (id)childForNode:(UIViewController *)node atIndex:(NSUInteger)index { - (id)childForNode:(UIViewController*)node atIndex:(NSUInteger)index {
return node.view; return node.view;
} }
- (void)setHighlightedForNode:(UIViewController *)node { - (void)setHighlightedForNode:(UIViewController*)node {
} }
- (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 {
SKNodeDescriptor *descriptor = [self descriptorForClass: [UIView class]]; SKNodeDescriptor* descriptor = [self descriptorForClass:[UIView class]];
[descriptor setHighlighted: highlighted forNode: node.view]; [descriptor setHighlighted:highlighted forNode:node.view];
} }
- (void)hitTest:(SKTouch *)touch forNode:(UIViewController *)node { - (void)hitTest:(SKTouch*)touch forNode:(UIViewController*)node {
[touch continueWithChildIndex: 0 withOffset: (CGPoint){ 0, 0}]; [touch continueWithChildIndex:0 withOffset:(CGPoint){0, 0}];
} }
@end @end
#endif #endif

View File

@@ -11,7 +11,7 @@
#import "SKNodeDescriptor.h" #import "SKNodeDescriptor.h"
@interface SKViewDescriptor : SKNodeDescriptor<UIView *> @interface SKViewDescriptor : SKNodeDescriptor<UIView*>
@end @end

View File

@@ -9,59 +9,61 @@
#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
static NSDictionary *YGDirectionEnumMap = nil; static NSDictionary* YGDirectionEnumMap = nil;
static NSDictionary *YGFlexDirectionEnumMap = nil; static NSDictionary* YGFlexDirectionEnumMap = nil;
static NSDictionary *YGJustifyEnumMap = nil; static NSDictionary* YGJustifyEnumMap = nil;
static NSDictionary *YGAlignEnumMap = nil; static NSDictionary* YGAlignEnumMap = nil;
static NSDictionary *YGPositionTypeEnumMap = nil; static NSDictionary* YGPositionTypeEnumMap = nil;
static NSDictionary *YGWrapEnumMap = nil; static NSDictionary* YGWrapEnumMap = nil;
static NSDictionary *YGOverflowEnumMap = nil; static NSDictionary* YGOverflowEnumMap = nil;
static NSDictionary *YGDisplayEnumMap = nil; static NSDictionary* YGDisplayEnumMap = nil;
static NSDictionary *YGUnitEnumMap = nil; static NSDictionary* YGUnitEnumMap = nil;
- (instancetype)initWithDescriptorMapper:(SKDescriptorMapper *)mapper { - (instancetype)initWithDescriptorMapper:(SKDescriptorMapper*)mapper {
if (self = [super initWithDescriptorMapper: mapper]) { if (self = [super initWithDescriptorMapper:mapper]) {
initEnumDictionaries(); initEnumDictionaries();
} }
return self; return self;
} }
- (NSString *)identifierForNode:(UIView *)node { - (NSString*)identifierForNode:(UIView*)node {
return [NSString stringWithFormat: @"%p", node]; return [NSString stringWithFormat:@"%p", node];
} }
- (NSUInteger)childCountForNode:(UIView *)node { - (NSUInteger)childCountForNode:(UIView*)node {
return [[self validChildrenForNode: node] count]; return [[self validChildrenForNode:node] count];
} }
- (id)childForNode:(UIView *)node atIndex:(NSUInteger)index { - (id)childForNode:(UIView*)node atIndex:(NSUInteger)index {
return [[self validChildrenForNode:node] objectAtIndex: index]; return [[self validChildrenForNode:node] objectAtIndex:index];
} }
- (NSArray *)validChildrenForNode:(UIView *)node { - (NSArray*)validChildrenForNode:(UIView*)node {
NSMutableArray *validChildren = [NSMutableArray new]; NSMutableArray* validChildren = [NSMutableArray new];
// 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 &&
[validChildren addObject: child.nextResponder]; child.nextResponder != node.nextResponder) {
[validChildren addObject:child.nextResponder];
} else { } else {
[validChildren addObject: child]; [validChildren addObject:child];
} }
} }
} }
@@ -69,121 +71,165 @@ static NSDictionary *YGUnitEnumMap = nil;
return validChildren; return validChildren;
} }
- (NSArray<SKNamed<NSDictionary *> *> *)dataForNode:(UIView *)node { - (NSArray<SKNamed<NSDictionary*>*>*)dataForNode:(UIView*)node {
return [NSArray arrayWithObjects: return [NSArray
[SKNamed newWithName: @"UIView" arrayWithObjects:
withValue: @{ [SKNamed
@"frame": SKMutableObject(node.frame), newWithName:@"UIView"
@"bounds": SKObject(node.bounds), withValue:@{
@"center": SKObject(node.center), @"frame" : SKMutableObject(node.frame),
@"layoutMargins": SKObject(node.layoutMargins), @"bounds" : SKObject(node.bounds),
@"clipsToBounds": @(node.clipsToBounds), @"center" : SKObject(node.center),
@"alpha": SKMutableObject(@(node.alpha)), @"layoutMargins" : SKObject(node.layoutMargins),
@"tag": @(node.tag), @"clipsToBounds" : @(node.clipsToBounds),
@"backgroundColor": SKMutableObject(node.backgroundColor) @"alpha" : SKMutableObject(@(node.alpha)),
}], @"tag" : @(node.tag),
[SKNamed newWithName: @"CALayer" @"backgroundColor" : SKMutableObject(node.backgroundColor)
withValue: @{ }],
@"shadowColor": SKMutableObject([UIColor colorWithCGColor:node.layer.shadowColor]), [SKNamed
@"shadowOpacity": SKMutableObject(@(node.layer.shadowOpacity)), newWithName:@"CALayer"
@"shadowRadius": SKMutableObject(@(node.layer.shadowRadius)), withValue:@{
@"shadowOffset": SKMutableObject(node.layer.shadowOffset), @"shadowColor" : SKMutableObject(
@"backgroundColor": SKMutableObject([UIColor colorWithCGColor:node.layer.backgroundColor]), [UIColor colorWithCGColor:node.layer.shadowColor]),
@"borderColor": SKMutableObject([UIColor colorWithCGColor:node.layer.borderColor]), @"shadowOpacity" :
@"borderWidth": SKMutableObject(@(node.layer.borderWidth)), SKMutableObject(@(node.layer.shadowOpacity)),
@"cornerRadius": SKMutableObject(@(node.layer.cornerRadius)), @"shadowRadius" : SKMutableObject(@(node.layer.shadowRadius)),
@"masksToBounds": SKMutableObject(@(node.layer.masksToBounds)), @"shadowOffset" : SKMutableObject(node.layer.shadowOffset),
}], @"backgroundColor" : SKMutableObject(
[SKNamed newWithName: @"Accessibility" [UIColor colorWithCGColor:node.layer.backgroundColor]),
withValue: @{ @"borderColor" : SKMutableObject(
@"isAccessibilityElement": SKMutableObject(@(node.isAccessibilityElement)), [UIColor colorWithCGColor:node.layer.borderColor]),
@"accessibilityLabel": SKMutableObject(node.accessibilityLabel ?: @""), @"borderWidth" : SKMutableObject(@(node.layer.borderWidth)),
@"accessibilityIdentifier": SKMutableObject(node.accessibilityIdentifier ?: @""), @"cornerRadius" : SKMutableObject(@(node.layer.cornerRadius)),
@"accessibilityValue": SKMutableObject(node.accessibilityValue ?: @""), @"masksToBounds" :
@"accessibilityHint": SKMutableObject(node.accessibilityHint ?: @""), SKMutableObject(@(node.layer.masksToBounds)),
@"accessibilityTraits": AccessibilityTraitsDict(node.accessibilityTraits), }],
@"accessibilityViewIsModal": SKMutableObject(@(node.accessibilityViewIsModal)), [SKNamed newWithName:@"Accessibility"
@"shouldGroupAccessibilityChildren": SKMutableObject(@(node.shouldGroupAccessibilityChildren)), withValue:@{
}], @"isAccessibilityElement" :
!node.isYogaEnabled ? nil : SKMutableObject(@(node.isAccessibilityElement)),
[SKNamed newWithName: @"YGLayout" @"accessibilityLabel" :
withValue: @{ SKMutableObject(node.accessibilityLabel ?: @""),
@"direction": SKMutableObject(YGDirectionEnumMap[@(node.yoga.direction)]), @"accessibilityIdentifier" :
@"justifyContent": SKMutableObject(YGJustifyEnumMap[@(node.yoga.justifyContent)]), SKMutableObject(node.accessibilityIdentifier ?: @""),
@"aligns": @{ @"accessibilityValue" :
@"alignContent": SKMutableObject(YGAlignEnumMap[@(node.yoga.alignContent)]), SKMutableObject(node.accessibilityValue ?: @""),
@"alignItems": SKMutableObject(YGAlignEnumMap[@(node.yoga.alignItems)]), @"accessibilityHint" :
@"alignSelf": SKMutableObject(YGAlignEnumMap[@(node.yoga.alignSelf)]), SKMutableObject(node.accessibilityHint ?: @""),
}, @"accessibilityTraits" :
@"position": @{ AccessibilityTraitsDict(node.accessibilityTraits),
@"type": SKMutableObject(YGPositionTypeEnumMap[@(node.yoga.position)]), @"accessibilityViewIsModal" :
@"left": SKYGValueObject(node.yoga.left), SKMutableObject(@(node.accessibilityViewIsModal)),
@"top": SKYGValueObject(node.yoga.top), @"shouldGroupAccessibilityChildren" : SKMutableObject(
@"right": SKYGValueObject(node.yoga.right), @(node.shouldGroupAccessibilityChildren)),
@"bottom": SKYGValueObject(node.yoga.bottom), }],
@"start": SKYGValueObject(node.yoga.start), !node.isYogaEnabled
@"end": SKYGValueObject(node.yoga.end), ? nil
}, : [SKNamed
@"overflow": SKMutableObject(YGOverflowEnumMap[@(node.yoga.overflow)]), newWithName:@"YGLayout"
@"display": SKMutableObject(YGDisplayEnumMap[@(node.yoga.display)]), withValue:@{
@"flex": @{ @"direction" : SKMutableObject(
@"flexDirection": SKMutableObject(YGFlexDirectionEnumMap[@(node.yoga.flexDirection)]), YGDirectionEnumMap[@(node.yoga.direction)]),
@"flexWrap": SKMutableObject(YGWrapEnumMap[@(node.yoga.flexWrap)]), @"justifyContent" : SKMutableObject(
@"flexGrow": SKMutableObject(@(node.yoga.flexGrow)), YGJustifyEnumMap[@(node.yoga.justifyContent)]),
@"flexShrink": SKMutableObject(@(node.yoga.flexShrink)), @"aligns" : @{
@"flexBasis": SKYGValueObject(node.yoga.flexBasis), @"alignContent" : SKMutableObject(
}, YGAlignEnumMap[@(node.yoga.alignContent)]),
@"margin": @{ @"alignItems" : SKMutableObject(
@"left": SKYGValueObject(node.yoga.marginLeft), YGAlignEnumMap[@(node.yoga.alignItems)]),
@"top": SKYGValueObject(node.yoga.marginTop), @"alignSelf" : SKMutableObject(
@"right": SKYGValueObject(node.yoga.marginRight), YGAlignEnumMap[@(node.yoga.alignSelf)]),
@"bottom": SKYGValueObject(node.yoga.marginBottom), },
@"start": SKYGValueObject(node.yoga.marginStart), @"position" : @{
@"end": SKYGValueObject(node.yoga.marginEnd), @"type" : SKMutableObject(
@"horizontal": SKYGValueObject(node.yoga.marginHorizontal), YGPositionTypeEnumMap[@(node.yoga.position)]),
@"vertical": SKYGValueObject(node.yoga.marginVertical), @"left" : SKYGValueObject(node.yoga.left),
@"all": SKYGValueObject(node.yoga.margin), @"top" : SKYGValueObject(node.yoga.top),
}, @"right" : SKYGValueObject(node.yoga.right),
@"padding": @{ @"bottom" : SKYGValueObject(node.yoga.bottom),
@"left": SKYGValueObject(node.yoga.paddingLeft), @"start" : SKYGValueObject(node.yoga.start),
@"top": SKYGValueObject(node.yoga.paddingTop), @"end" : SKYGValueObject(node.yoga.end),
@"right": SKYGValueObject(node.yoga.paddingRight), },
@"bottom": SKYGValueObject(node.yoga.paddingBottom), @"overflow" : SKMutableObject(
@"start": SKYGValueObject(node.yoga.paddingStart), YGOverflowEnumMap[@(node.yoga.overflow)]),
@"end": SKYGValueObject(node.yoga.paddingEnd), @"display" : SKMutableObject(
@"horizontal": SKYGValueObject(node.yoga.paddingHorizontal), YGDisplayEnumMap[@(node.yoga.display)]),
@"vertical": SKYGValueObject(node.yoga.paddingVertical), @"flex" : @{
@"all": SKYGValueObject(node.yoga.padding), @"flexDirection" :
}, SKMutableObject(YGFlexDirectionEnumMap[
@"border": @{ @(node.yoga.flexDirection)]),
@"leftWidth": SKMutableObject(@(node.yoga.borderLeftWidth)), @"flexWrap" : SKMutableObject(
@"topWidth": SKMutableObject(@(node.yoga.borderTopWidth)), YGWrapEnumMap[@(node.yoga.flexWrap)]),
@"rightWidth": SKMutableObject(@(node.yoga.borderRightWidth)), @"flexGrow" : SKMutableObject(@(node.yoga.flexGrow)),
@"bottomWidth": SKMutableObject(@(node.yoga.borderBottomWidth)), @"flexShrink" :
@"startWidth": SKMutableObject(@(node.yoga.borderStartWidth)), SKMutableObject(@(node.yoga.flexShrink)),
@"endWidth": SKMutableObject(@(node.yoga.borderEndWidth)), @"flexBasis" : SKYGValueObject(node.yoga.flexBasis),
@"all": SKMutableObject(@(node.yoga.borderWidth)), },
}, @"margin" : @{
@"dimensions": @{ @"left" : SKYGValueObject(node.yoga.marginLeft),
@"width": SKYGValueObject(node.yoga.width), @"top" : SKYGValueObject(node.yoga.marginTop),
@"height": SKYGValueObject(node.yoga.height), @"right" : SKYGValueObject(node.yoga.marginRight),
@"minWidth": SKYGValueObject(node.yoga.minWidth), @"bottom" : SKYGValueObject(node.yoga.marginBottom),
@"minHeight": SKYGValueObject(node.yoga.minHeight), @"start" : SKYGValueObject(node.yoga.marginStart),
@"maxWidth": SKYGValueObject(node.yoga.maxWidth), @"end" : SKYGValueObject(node.yoga.marginEnd),
@"maxHeight": SKYGValueObject(node.yoga.maxHeight), @"horizontal" :
}, SKYGValueObject(node.yoga.marginHorizontal),
@"aspectRatio": SKMutableObject(@(node.yoga.aspectRatio)), @"vertical" :
@"resolvedDirection": SKObject(YGDirectionEnumMap[@(node.yoga.resolvedDirection)]), SKYGValueObject(node.yoga.marginVertical),
}], @"all" : SKYGValueObject(node.yoga.margin),
},
@"padding" : @{
@"left" : SKYGValueObject(node.yoga.paddingLeft),
@"top" : SKYGValueObject(node.yoga.paddingTop),
@"right" : SKYGValueObject(node.yoga.paddingRight),
@"bottom" : SKYGValueObject(node.yoga.paddingBottom),
@"start" : SKYGValueObject(node.yoga.paddingStart),
@"end" : SKYGValueObject(node.yoga.paddingEnd),
@"horizontal" :
SKYGValueObject(node.yoga.paddingHorizontal),
@"vertical" :
SKYGValueObject(node.yoga.paddingVertical),
@"all" : SKYGValueObject(node.yoga.padding),
},
@"border" : @{
@"leftWidth" :
SKMutableObject(@(node.yoga.borderLeftWidth)),
@"topWidth" :
SKMutableObject(@(node.yoga.borderTopWidth)),
@"rightWidth" :
SKMutableObject(@(node.yoga.borderRightWidth)),
@"bottomWidth" :
SKMutableObject(@(node.yoga.borderBottomWidth)),
@"startWidth" :
SKMutableObject(@(node.yoga.borderStartWidth)),
@"endWidth" :
SKMutableObject(@(node.yoga.borderEndWidth)),
@"all" : SKMutableObject(@(node.yoga.borderWidth)),
},
@"dimensions" : @{
@"width" : SKYGValueObject(node.yoga.width),
@"height" : SKYGValueObject(node.yoga.height),
@"minWidth" : SKYGValueObject(node.yoga.minWidth),
@"minHeight" : SKYGValueObject(node.yoga.minHeight),
@"maxWidth" : SKYGValueObject(node.yoga.maxWidth),
@"maxHeight" : SKYGValueObject(node.yoga.maxHeight),
},
@"aspectRatio" :
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,43 +461,43 @@ 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 {
SKHighlightOverlay *overlay = [SKHighlightOverlay sharedInstance]; SKHighlightOverlay* overlay = [SKHighlightOverlay sharedInstance];
if (highlighted == YES) { if (highlighted == YES) {
[overlay mountInView: node withFrame: node.bounds]; [overlay mountInView:node withFrame:node.bounds];
} else { } else {
[overlay unmount]; [overlay unmount];
} }
} }
- (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;
id<NSObject> childNode = [self childForNode: node atIndex: index]; index--) {
UIView *viewForNode = nil; id<NSObject> childNode = [self childForNode:node atIndex:index];
UIView* viewForNode = nil;
if ([childNode isKindOfClass: [UIViewController class]]) { if ([childNode isKindOfClass:[UIViewController class]]) {
UIViewController *child = (UIViewController *)childNode; UIViewController* child = (UIViewController*)childNode;
viewForNode = child.view; viewForNode = child.view;
} else { } else {
viewForNode = (UIView *)childNode; viewForNode = (UIView*)childNode;
} }
if (viewForNode.isHidden || viewForNode.alpha <= 0) { if (viewForNode.isHidden || viewForNode.alpha <= 0) {
continue; continue;
} }
if ([touch containedIn: viewForNode.frame]) { if ([touch containedIn:viewForNode.frame]) {
[touch continueWithChildIndex: index withOffset: viewForNode.frame.origin ]; [touch continueWithChildIndex:index withOffset:viewForNode.frame.origin];
return; return;
} }
} }
@@ -463,73 +509,73 @@ static void initEnumDictionaries() {
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{
YGDirectionEnumMap = @{ YGDirectionEnumMap = @{
@(YGDirectionInherit): @"inherit", @(YGDirectionInherit) : @"inherit",
@(YGDirectionLTR): @"LTR", @(YGDirectionLTR) : @"LTR",
@(YGDirectionRTL): @"RTL", @(YGDirectionRTL) : @"RTL",
}; };
YGFlexDirectionEnumMap = @{ YGFlexDirectionEnumMap = @{
@(YGFlexDirectionColumn): @"column", @(YGFlexDirectionColumn) : @"column",
@(YGFlexDirectionColumnReverse): @"column-reverse", @(YGFlexDirectionColumnReverse) : @"column-reverse",
@(YGFlexDirectionRow): @"row", @(YGFlexDirectionRow) : @"row",
@(YGFlexDirectionRowReverse): @"row-reverse", @(YGFlexDirectionRowReverse) : @"row-reverse",
}; };
YGJustifyEnumMap = @{ YGJustifyEnumMap = @{
@(YGJustifyFlexStart): @"flex-start", @(YGJustifyFlexStart) : @"flex-start",
@(YGJustifyCenter): @"center", @(YGJustifyCenter) : @"center",
@(YGJustifyFlexEnd): @"flex-end", @(YGJustifyFlexEnd) : @"flex-end",
@(YGJustifySpaceBetween): @"space-between", @(YGJustifySpaceBetween) : @"space-between",
@(YGJustifySpaceAround): @"space-around", @(YGJustifySpaceAround) : @"space-around",
}; };
YGAlignEnumMap = @{ YGAlignEnumMap = @{
@(YGAlignAuto): @"auto", @(YGAlignAuto) : @"auto",
@(YGAlignFlexStart): @"flex-start", @(YGAlignFlexStart) : @"flex-start",
@(YGAlignCenter): @"end", @(YGAlignCenter) : @"end",
@(YGAlignFlexEnd): @"flex-end", @(YGAlignFlexEnd) : @"flex-end",
@(YGAlignStretch): @"stretch", @(YGAlignStretch) : @"stretch",
@(YGAlignBaseline): @"baseline", @(YGAlignBaseline) : @"baseline",
@(YGAlignSpaceBetween): @"space-between", @(YGAlignSpaceBetween) : @"space-between",
@(YGAlignSpaceAround): @"space-around", @(YGAlignSpaceAround) : @"space-around",
}; };
YGPositionTypeEnumMap = @{ YGPositionTypeEnumMap = @{
@(YGPositionTypeRelative): @"relative", @(YGPositionTypeRelative) : @"relative",
@(YGPositionTypeAbsolute): @"absolute", @(YGPositionTypeAbsolute) : @"absolute",
}; };
YGWrapEnumMap = @{ YGWrapEnumMap = @{
@(YGWrapNoWrap): @"no-wrap", @(YGWrapNoWrap) : @"no-wrap",
@(YGWrapWrap): @"wrap", @(YGWrapWrap) : @"wrap",
@(YGWrapWrapReverse): @"wrap-reverse", @(YGWrapWrapReverse) : @"wrap-reverse",
}; };
YGOverflowEnumMap = @{ YGOverflowEnumMap = @{
@(YGOverflowVisible): @"visible", @(YGOverflowVisible) : @"visible",
@(YGOverflowHidden): @"hidden", @(YGOverflowHidden) : @"hidden",
@(YGOverflowScroll): @"scroll", @(YGOverflowScroll) : @"scroll",
}; };
YGDisplayEnumMap = @{ YGDisplayEnumMap = @{
@(YGDisplayFlex): @"flex", @(YGDisplayFlex) : @"flex",
@(YGDisplayNone): @"none", @(YGDisplayNone) : @"none",
}; };
YGUnitEnumMap = @{ YGUnitEnumMap = @{
@(YGUnitUndefined): @"undefined", @(YGUnitUndefined) : @"undefined",
@(YGUnitPoint): @"point", @(YGUnitPoint) : @"point",
@(YGUnitPercent): @"percent", @(YGUnitPercent) : @"percent",
@(YGUnitAuto): @"auto", @(YGUnitAuto) : @"auto",
}; };
}); });
} }
static NSDictionary *SKYGValueObject(YGValue value) { static NSDictionary* SKYGValueObject(YGValue value) {
return @{ return @{
@"value": SKMutableObject(@(value.value)), @"value" : SKMutableObject(@(value.value)),
@"unit": SKMutableObject(YGUnitEnumMap[@(value.unit)]), @"unit" : SKMutableObject(YGUnitEnumMap[@(value.unit)]),
}; };
} }
/* /*
@@ -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(
NSMutableDictionary *traitsDict = [NSMutableDictionary new]; UIAccessibilityTraits accessibilityTraits) {
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

@@ -12,8 +12,8 @@
as keys in C++ STL as keys in C++ STL
*/ */
class SKObjectHash { class SKObjectHash {
public: public:
size_t operator()(const NSObject *x) const { size_t operator()(const NSObject* x) const {
return (size_t)[x hash]; return (size_t)[x hash];
} }
}; };

View File

@@ -16,14 +16,18 @@ 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(
method_getImplementation(swissledMethod), cls,
method_getTypeEncoding(swissledMethod)); original,
method_getImplementation(swissledMethod),
method_getTypeEncoding(swissledMethod));
if (didAddMethod) { if (didAddMethod) {
class_replaceMethod(cls, swissled, class_replaceMethod(
method_getImplementation(originalMethod), cls,
method_getTypeEncoding(originalMethod)); swissled,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else { } else {
method_exchangeImplementations(originalMethod, swissledMethod); method_exchangeImplementations(originalMethod, swissledMethod);
} }

View File

@@ -7,25 +7,31 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#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]; \
node.yoga.varName = (enumName)[varName unsignedIntegerValue]; \ if (varName == nil) { \
} return; \
} \
node.yoga.varName = (enumName)[varName unsignedIntegerValue]; \
}
#define APPLY_VALUE_TO_YGVALUE(varName) \ #define APPLY_VALUE_TO_YGVALUE(varName) \
^(NSNumber *value) { \ ^(NSNumber * value) { \
YGValue newValue = node.yoga.varName; \ YGValue newValue = node.yoga.varName; \
newValue.value = [value floatValue]; \ newValue.value = [value floatValue]; \
node.yoga.varName = newValue; \ 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]; \
YGValue newValue = node.yoga.varName; \ if (varName == nil) { \
newValue.unit = (enumName)[varName unsignedIntegerValue]; \ return; \
node.yoga.varName = newValue; \ } \
} YGValue newValue = node.yoga.varName; \
newValue.unit = (enumName)[varName unsignedIntegerValue]; \
node.yoga.varName = newValue; \
}

View File

@@ -7,8 +7,8 @@
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
@protocol FKTextSearchable <NSObject> @protocol FKTextSearchable<NSObject>
- (NSString *)searchableText; - (NSString*)searchableText;
@end @end

View File

@@ -7,9 +7,8 @@
#import "SKTapListenerMock.h" #import "SKTapListenerMock.h"
@implementation SKTapListenerMock @implementation SKTapListenerMock {
{ NSMutableArray<SKTapReceiver>* _tapReceivers;
NSMutableArray<SKTapReceiver> *_tapReceivers;
} }
@synthesize isMounted; @synthesize isMounted;
@@ -23,7 +22,7 @@
} }
- (void)listenForTapWithBlock:(SKTapReceiver)receiver { - (void)listenForTapWithBlock:(SKTapReceiver)receiver {
[_tapReceivers addObject: receiver]; [_tapReceivers addObject:receiver];
} }
- (void)tapAt:(CGPoint)point { - (void)tapAt:(CGPoint)point {

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,9 +22,8 @@
@interface SonarKitLayoutPluginTests : XCTestCase @interface SonarKitLayoutPluginTests : XCTestCase
@end @end
@implementation SonarKitLayoutPluginTests @implementation SonarKitLayoutPluginTests {
{ SKDescriptorMapper* _descriptorMapper;
SKDescriptorMapper *_descriptorMapper;
} }
- (void)setUp { - (void)setUp {
@@ -32,217 +31,235 @@
_descriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults]; _descriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults];
[_descriptorMapper registerDescriptor: [TestNodeDescriptor new] [_descriptorMapper registerDescriptor:[TestNodeDescriptor new]
forClass: [TestNode class]]; forClass:[TestNode class]];
} }
- (void)testGetRoot { - (void)testGetRoot {
FlipperKitLayoutPlugin *plugin = [[FlipperKitLayoutPlugin alloc] FlipperKitLayoutPlugin* plugin = [[FlipperKitLayoutPlugin alloc]
initWithRootNode: [[TestNode alloc] initWithName: @"rootNode"] initWithRootNode:[[TestNode alloc] initWithName:@"rootNode"]
withTapListener: nil withTapListener:nil
withDescriptorMapper: _descriptorMapper]; withDescriptorMapper:_descriptorMapper];
FlipperConnectionMock *connection = [FlipperConnectionMock new]; FlipperConnectionMock* connection = [FlipperConnectionMock new];
FlipperResponderMock *responder = [FlipperResponderMock new]; FlipperResponderMock* responder = [FlipperResponderMock new];
[plugin didConnect:connection]; [plugin didConnect:connection];
SonarReceiver receiver = connection.receivers[@"getRoot"]; SonarReceiver receiver = connection.receivers[@"getRoot"];
receiver(@{}, responder); receiver(@{}, responder);
XCTAssertTrue(([responder.successes containsObject: @{ XCTAssertTrue(([responder.successes containsObject:@{
@"id": @"rootNode", @"id" : @"rootNode",
@"name": @"TestNode", @"name" : @"TestNode",
@"children": @[], @"children" : @[],
@"attributes": @[], @"attributes" : @[],
@"data": @{}, @"data" : @{},
@"decoration": @"", @"decoration" : @"",
}])); }]));
} }
- (void)testGetEmptyNodes { - (void)testGetEmptyNodes {
FlipperKitLayoutPlugin *plugin = [FlipperKitLayoutPlugin new]; FlipperKitLayoutPlugin* plugin = [FlipperKitLayoutPlugin new];
FlipperConnectionMock *connection = [FlipperConnectionMock new]; FlipperConnectionMock* connection = [FlipperConnectionMock new];
FlipperResponderMock *responder = [FlipperResponderMock new]; FlipperResponderMock* responder = [FlipperResponderMock new];
[plugin didConnect:connection]; [plugin didConnect:connection];
SonarReceiver receiver = connection.receivers[@"getNodes"]; SonarReceiver receiver = connection.receivers[@"getNodes"];
receiver(@{@"ids": @[]}, responder); receiver(@{@"ids" : @[]}, responder);
XCTAssertTrue(([responder.successes containsObject:@{@"elements": @[]}])); XCTAssertTrue(([responder.successes containsObject:@{@"elements" : @[]}]));
} }
- (void)testGetNodes { - (void)testGetNodes {
TestNode *rootNode = [[TestNode alloc] initWithName: @"rootNode"]; TestNode* rootNode = [[TestNode alloc] initWithName:@"rootNode"];
NSArray *childNodes = @[ NSArray* childNodes = @[
[[TestNode alloc] initWithName: @"testNode1"], [[TestNode alloc] initWithName:@"testNode1"],
[[TestNode alloc] initWithName: @"testNode2"], [[TestNode alloc] initWithName:@"testNode2"],
[[TestNode alloc] initWithName: @"testNode3"], [[TestNode alloc] initWithName:@"testNode3"],
]; ];
rootNode.children = childNodes; rootNode.children = childNodes;
FlipperKitLayoutPlugin *plugin = [[FlipperKitLayoutPlugin alloc] initWithRootNode: rootNode FlipperKitLayoutPlugin* plugin =
withTapListener: nil [[FlipperKitLayoutPlugin alloc] initWithRootNode:rootNode
withDescriptorMapper: _descriptorMapper]; withTapListener:nil
withDescriptorMapper:_descriptorMapper];
FlipperConnectionMock *connection = [FlipperConnectionMock new]; FlipperConnectionMock* connection = [FlipperConnectionMock new];
FlipperResponderMock *responder = [FlipperResponderMock new]; FlipperResponderMock* responder = [FlipperResponderMock new];
[plugin didConnect:connection]; [plugin didConnect:connection];
// Ensure that nodes are tracked // Ensure that nodes are tracked
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", @{
@"name": @"TestNode", @"id" : @"testNode1",
@"children": @[], @"name" : @"TestNode",
@"attributes": @[], @"children" : @[],
@"data": @{}, @"attributes" : @[],
@"decoration": @"", @"data" : @{},
}, @"decoration" : @"",
@{ },
@"id": @"testNode2", @{
@"name": @"TestNode", @"id" : @"testNode2",
@"children": @[], @"name" : @"TestNode",
@"attributes": @[], @"children" : @[],
@"data": @{}, @"attributes" : @[],
@"decoration": @"", @"data" : @{},
}, @"decoration" : @"",
@{ },
@"id": @"testNode3", @{
@"name": @"TestNode", @"id" : @"testNode3",
@"children": @[], @"name" : @"TestNode",
@"attributes": @[], @"children" : @[],
@"data": @{}, @"attributes" : @[],
@"decoration": @"", @"data" : @{},
}, @"decoration" : @"",
]}])); },
]
}]));
} }
- (void)testSetHighlighted { - (void)testSetHighlighted {
TestNode *rootNode = [[TestNode alloc] initWithName: @"rootNode"]; TestNode* rootNode = [[TestNode alloc] initWithName:@"rootNode"];
TestNode *testNode1 = [[TestNode alloc] initWithName: @"testNode1"]; TestNode* testNode1 = [[TestNode alloc] initWithName:@"testNode1"];
TestNode *testNode2 = [[TestNode alloc] initWithName: @"testNode2"]; TestNode* testNode2 = [[TestNode alloc] initWithName:@"testNode2"];
NSArray *childNodes = @[ testNode1, testNode2 ]; NSArray* childNodes = @[ testNode1, testNode2 ];
rootNode.children = childNodes; rootNode.children = childNodes;
FlipperKitLayoutPlugin *plugin = [[FlipperKitLayoutPlugin alloc] initWithRootNode: rootNode FlipperKitLayoutPlugin* plugin =
withTapListener: nil [[FlipperKitLayoutPlugin alloc] initWithRootNode:rootNode
withDescriptorMapper: _descriptorMapper]; withTapListener:nil
withDescriptorMapper:_descriptorMapper];
FlipperConnectionMock *connection = [FlipperConnectionMock new]; FlipperConnectionMock* connection = [FlipperConnectionMock new];
FlipperResponderMock *responder = [FlipperResponderMock new]; FlipperResponderMock* responder = [FlipperResponderMock new];
[plugin didConnect:connection]; [plugin didConnect:connection];
// Setup in order to track nodes successfully // Setup in order to track nodes successfully
connection.receivers[@"getRoot"](@{}, responder); connection.receivers[@"getRoot"](@{}, responder);
SonarReceiver getNodesCall = connection.receivers[@"getNodes"]; SonarReceiver getNodesCall = connection.receivers[@"getNodes"];
getNodesCall(@{@"ids": @[ @"testNode1", @"testNode2" ]}, responder); getNodesCall(@{@"ids" : @[ @"testNode1", @"testNode2" ]}, responder);
SonarReceiver setHighlighted = connection.receivers[@"setHighlighted"]; SonarReceiver setHighlighted = connection.receivers[@"setHighlighted"];
setHighlighted(@{@"id":@"testNode2"}, responder); setHighlighted(@{@"id" : @"testNode2"}, responder);
XCTAssertTrue(testNode2.highlighted); XCTAssertTrue(testNode2.highlighted);
setHighlighted(@{@"id":@"testNode1"}, responder); setHighlighted(@{@"id" : @"testNode1"}, responder);
// Ensure that old highlight was removed // Ensure that old highlight was removed
XCTAssertTrue(testNode1.highlighted && !testNode2.highlighted); XCTAssertTrue(testNode1.highlighted && !testNode2.highlighted);
} }
- (void)testSetSearchActive { - (void)testSetSearchActive {
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 =
withFrame: CGRectMake(20, 20, 20, 20)]; [[TestNode alloc] initWithName:@"testNode1"
TestNode *testNode2 = [[TestNode alloc] initWithName: @"testNode2" withFrame:CGRectMake(20, 20, 20, 20)];
withFrame: CGRectMake(20, 40, 20, 20)]; TestNode* testNode2 =
TestNode *testNode3 = [[TestNode alloc] initWithName: @"testNode3" [[TestNode alloc] initWithName:@"testNode2"
withFrame: CGRectMake(25, 42, 5, 5)]; withFrame:CGRectMake(20, 40, 20, 20)];
TestNode* testNode3 =
[[TestNode alloc] initWithName:@"testNode3"
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 =
withTapListener: tapListener [[FlipperKitLayoutPlugin alloc] initWithRootNode:rootNode
withDescriptorMapper: _descriptorMapper]; withTapListener:tapListener
withDescriptorMapper:_descriptorMapper];
FlipperConnectionMock *connection = [FlipperConnectionMock new]; FlipperConnectionMock* connection = [FlipperConnectionMock new];
FlipperResponderMock *responder = [FlipperResponderMock new]; FlipperResponderMock* responder = [FlipperResponderMock new];
[plugin didConnect:connection]; [plugin didConnect:connection];
connection.receivers[@"setSearchActive"](@{@"active":@YES}, responder); connection.receivers[@"setSearchActive"](@{@"active" : @YES}, responder);
// 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 =
withTapListener: tapListener [[FlipperKitLayoutPlugin alloc] initWithRootNode:rootNode
withDescriptorMapper: _descriptorMapper]; withTapListener:tapListener
withDescriptorMapper:_descriptorMapper];
FlipperConnectionMock *connection = [FlipperConnectionMock new]; FlipperConnectionMock* connection = [FlipperConnectionMock new];
FlipperResponderMock *responder = [FlipperResponderMock new]; FlipperResponderMock* responder = [FlipperResponderMock new];
[plugin didConnect:connection]; [plugin didConnect:connection];
SonarReceiver setSearchActive = connection.receivers[@"setSearchActive"]; SonarReceiver setSearchActive = connection.receivers[@"setSearchActive"];
setSearchActive(@{@"active":@YES}, responder); setSearchActive(@{@"active" : @YES}, responder);
XCTAssertTrue(tapListener.isMounted); XCTAssertTrue(tapListener.isMounted);
setSearchActive(@{@"active":@NO}, responder); setSearchActive(@{@"active" : @NO}, responder);
XCTAssertTrue(! tapListener.isMounted); XCTAssertTrue(!tapListener.isMounted);
} }
- (void)testSetData { - (void)testSetData {
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 =
withFrame: CGRectMake(20, 20, 20, 20)]; [[TestNode alloc] initWithName:@"testNode1"
TestNode *testNode2 = [[TestNode alloc] initWithName: @"testNode2" withFrame:CGRectMake(20, 20, 20, 20)];
withFrame: CGRectMake(20, 40, 20, 20)]; TestNode* testNode2 =
TestNode *testNode3 = [[TestNode alloc] initWithName: @"testNode3" [[TestNode alloc] initWithName:@"testNode2"
withFrame: CGRectMake(25, 42, 5, 5)]; withFrame:CGRectMake(20, 40, 20, 20)];
TestNode* testNode3 =
[[TestNode alloc] initWithName:@"testNode3"
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 =
withTapListener: tapListener [[FlipperKitLayoutPlugin alloc] initWithRootNode:rootNode
withDescriptorMapper: _descriptorMapper]; withTapListener:tapListener
withDescriptorMapper:_descriptorMapper];
FlipperConnectionMock *connection = [FlipperConnectionMock new]; FlipperConnectionMock* connection = [FlipperConnectionMock new];
FlipperResponderMock *responder = [FlipperResponderMock new]; FlipperResponderMock* responder = [FlipperResponderMock new];
[plugin didConnect:connection]; [plugin didConnect:connection];
// Setup in order to track nodes successfully // Setup in order to track nodes successfully
connection.receivers[@"getRoot"](@{}, responder); connection.receivers[@"getRoot"](@{}, responder);
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", @{
@"path": @[ @"TestNode", @"name" ], @"id" : @"testNode3",
@"value": @"changedNameForTestNode3", @"path" : @[ @"TestNode", @"name" ],
}, responder); @"value" : @"changedNameForTestNode3",
},
responder);
XCTAssertTrue([testNode3.nodeName isEqualToString: @"changedNameForTestNode3"]); XCTAssertTrue(
[testNode3.nodeName isEqualToString:@"changedNameForTestNode3"]);
} }
@end @end

View File

@@ -9,13 +9,13 @@
@interface TestNode : NSObject @interface TestNode : NSObject
@property (nonatomic, copy) NSString *nodeName; @property(nonatomic, copy) NSString* nodeName;
@property (nonatomic, copy) NSArray<TestNode *> *children; @property(nonatomic, copy) NSArray<TestNode*>* children;
@property (nonatomic, assign) BOOL highlighted; @property(nonatomic, assign) BOOL highlighted;
@property (nonatomic, assign) CGRect frame; @property(nonatomic, assign) CGRect frame;
- (instancetype)initWithName:(NSString *)name; - (instancetype)initWithName:(NSString*)name;
- (instancetype)initWithName:(NSString *)name withFrame:(CGRect)frame; - (instancetype)initWithName:(NSString*)name withFrame:(CGRect)frame;
@end @end

View File

@@ -9,12 +9,11 @@
@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 {
if (self = [super init]) { if (self = [super init]) {
_nodeName = name; _nodeName = name;
_frame = frame; _frame = frame;

View File

@@ -9,5 +9,5 @@
#import "TestNode.h" #import "TestNode.h"
@interface TestNodeDescriptor : SKNodeDescriptor<TestNode *> @interface TestNodeDescriptor : SKNodeDescriptor<TestNode*>
@end @end

View File

@@ -9,27 +9,27 @@
@implementation TestNodeDescriptor @implementation TestNodeDescriptor
- (NSString *)identifierForNode:(TestNode *)node { - (NSString*)identifierForNode:(TestNode*)node {
return node.nodeName; return node.nodeName;
} }
- (NSUInteger)childCountForNode:(TestNode *)node { - (NSUInteger)childCountForNode:(TestNode*)node {
return [node.children count]; return [node.children count];
} }
- (id)childForNode:(TestNode *)node atIndex:(NSUInteger)index { - (id)childForNode:(TestNode*)node atIndex:(NSUInteger)index {
return [node.children objectAtIndex: index]; return [node.children objectAtIndex:index];
} }
- (void)setHighlighted:(BOOL)highlighted forNode:(TestNode *)node { - (void)setHighlighted:(BOOL)highlighted forNode:(TestNode*)node {
node.highlighted = highlighted; node.highlighted = highlighted;
} }
- (void)hitTest:(SKTouch *)touch forNode:(TestNode *)node { - (void)hitTest:(SKTouch*)touch forNode:(TestNode*)node {
NSUInteger index = [node.children count] - 1; NSUInteger index = [node.children count] - 1;
for (TestNode *childNode in [node.children reverseObjectEnumerator]) { for (TestNode* childNode in [node.children reverseObjectEnumerator]) {
if ([touch containedIn: childNode.frame]) { if ([touch containedIn:childNode.frame]) {
[touch continueWithChildIndex: index withOffset: node.frame.origin]; [touch continueWithChildIndex:index withOffset:node.frame.origin];
return; return;
} }
@@ -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,12 +13,16 @@
#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;
@end @end

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,68 +56,65 @@
#pragma mark - SKNetworkReporterDelegate #pragma mark - SKNetworkReporterDelegate
- (void)didObserveRequest:(SKRequestInfo*)request {
- (void)didObserveRequest:(SKRequestInfo *)request NSMutableArray<NSDictionary<NSString*, id>*>* headers = [NSMutableArray new];
{ for (NSString* key in [request.request.allHTTPHeaderFields allKeys]) {
NSMutableArray<NSDictionary<NSString *, id> *> *headers = [NSMutableArray new]; NSDictionary<NSString*, id>* header =
for (NSString *key in [request.request.allHTTPHeaderFields allKeys]) { @{@"key" : key, @"value" : request.request.allHTTPHeaderFields[key]};
NSDictionary<NSString *, id> *header = @{ [headers addObject:header];
@"key": key,
@"value": request.request.allHTTPHeaderFields[key]
};
[headers addObject: header];
} }
NSString *body = request.body; NSString* body = request.body;
[self send:@"newRequest" [self send:@"newRequest"
sonarObject:@{ sonarObject:@{
@"id": @(request.identifier), @"id" : @(request.identifier),
@"timestamp": @(request.timestamp), @"timestamp" : @(request.timestamp),
@"method": request.request.HTTPMethod ?: [NSNull null], @"method" : request.request.HTTPMethod ?: [NSNull null],
@"url": [request.request.URL absoluteString] ?: [NSNull null], @"url" : [request.request.URL absoluteString] ?: [NSNull null],
@"headers": headers, @"headers" : headers,
@"data": body ? body : [NSNull null] @"data" : body ? body : [NSNull null]
}]; }];
} }
- (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];
} }
NSString *body = response.body; NSString* body = response.body;
[self send:@"newResponse" [self send:@"newResponse"
sonarObject:@{ sonarObject:@{
@"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
@"headers": headers, localizedStringForStatusCode:httpResponse.statusCode]
@"data": body ? body : [NSNull null] ?: [NSNull null],
}]; @"headers" : headers,
@"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
if (self = [super initWithDispatchQueue:queue]) { dispatchQueue:
adapter.delegate = self; (std::shared_ptr<facebook::flipper::DispatchQueue>)
_adapter = adapter; queue {
} if (self = [super initWithDispatchQueue:queue]) {
return self; adapter.delegate = self;
_adapter = adapter;
}
return self;
} }
@end @end

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:
- (instancetype)initWithVectorEventSize:(NSUInteger)size connectionAccessQueue:(std::shared_ptr<facebook::flipper::DispatchQueue>)connectionAccessQueue; (std::shared_ptr<facebook::flipper::DispatchQueue>)
- (instancetype)initWithDispatchQueue:(std::shared_ptr<facebook::flipper::DispatchQueue>)queue; 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,12 +36,13 @@ 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;
} }
- (NSString *)identifier { - (NSString*)identifier {
// Note: This must match with the javascript pulgin identifier!! // Note: This must match with the javascript pulgin identifier!!
return @"Network"; return @"Network";
} }
@@ -62,9 +64,8 @@ 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(^{
if (self->_connection) { if (self->_connection) {
[self->_connection send:method withParams:sonarObject]; [self->_connection send:method withParams:sonarObject];
@@ -72,17 +73,15 @@ 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
});
} }
}); });
} }
- (void)sendBufferedEvents { - (void)sendBufferedEvents {
NSAssert(_connection, @"connection object cannot be nil"); NSAssert(_connection, @"connection object cannot be nil");
for (const auto &event : _ringBuffer) { for (const auto& event : _ringBuffer) {
[_connection send:event.method withParams:event.sonarObject]; [_connection send:event.method withParams:event.sonarObject];
} }
_ringBuffer.clear(); _ringBuffer.clear();
@@ -90,22 +89,23 @@ static const NSUInteger bufferSize = 500;
@end @end
@implementation SKBufferingPlugin(CPPInitialization) @implementation SKBufferingPlugin (CPPInitialization)
- (instancetype)initWithVectorEventSize:(NSUInteger)size connectionAccessQueue:(std::shared_ptr<facebook::flipper::DispatchQueue>)connectionAccessQueue { - (instancetype)initWithVectorEventSize:(NSUInteger)size
if (self = [super init]) { connectionAccessQueue:
_ringBuffer.reserve(size); (std::shared_ptr<facebook::flipper::DispatchQueue>)
_connectionAccessQueue = connectionAccessQueue; connectionAccessQueue {
} if (self = [super init]) {
return self; _ringBuffer.reserve(size);
_connectionAccessQueue = connectionAccessQueue;
}
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

@@ -12,31 +12,28 @@
#import <dispatch/dispatch.h> #import <dispatch/dispatch.h>
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);
}
virtual ~GCDQueue() { }
private:
dispatch_queue_t _underlyingQueue;
};
} }
}
virtual ~GCDQueue() {}
private:
dispatch_queue_t _underlyingQueue;
};
} // namespace flipper
} // namespace facebook
#endif #endif

View File

@@ -11,13 +11,13 @@
@protocol SKNetworkReporterDelegate @protocol SKNetworkReporterDelegate
- (void)didObserveRequest:(SKRequestInfo *)request; - (void)didObserveRequest:(SKRequestInfo*)request;
- (void)didObserveResponse:(SKResponseInfo *)response; - (void)didObserveResponse:(SKResponseInfo*)response;
@end @end
@protocol SKNetworkAdapterDelegate @protocol SKNetworkAdapterDelegate
@property (weak, nonatomic) id<SKNetworkReporterDelegate> delegate; @property(weak, nonatomic) id<SKNetworkReporterDelegate> delegate;
@end @end

View File

@@ -7,13 +7,16 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
@interface SKRequestInfo: NSObject @interface SKRequestInfo : NSObject
@property(assign, readwrite) int64_t identifier; @property(assign, readwrite) int64_t identifier;
@property(assign, readwrite) uint64_t timestamp; @property(assign, readwrite) uint64_t timestamp;
@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
- (void)setBodyFromData:(NSData * _Nullable)data; timestamp:(uint64_t)timestamp
request:(NSURLRequest*)request
data:(NSData*)data;
- (void)setBodyFromData:(NSData* _Nullable)data;
@end @end

View File

@@ -13,21 +13,23 @@
@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
if (self = [super init]){ request:(NSURLRequest*)request
data:(NSData*)data {
if (self = [super init]) {
_identifier = identifier; _identifier = identifier;
_timestamp = timestamp; _timestamp = timestamp;
_request = request; _request = request;
_body = data ? [data base64EncodedStringWithOptions: 0] _body = data ? [data base64EncodedStringWithOptions:0]
: [request.HTTPBody base64EncodedStringWithOptions: 0]; : [request.HTTPBody base64EncodedStringWithOptions:0];
} }
return self; return self;
} }
- (void)setBodyFromData:(NSData * _Nullable)data { - (void)setBodyFromData:(NSData* _Nullable)data {
self.body = data ? [data base64EncodedStringWithOptions: 0] self.body = data ? [data base64EncodedStringWithOptions:0]
: [self.request.HTTPBody base64EncodedStringWithOptions: 0]; : [self.request.HTTPBody base64EncodedStringWithOptions:0];
} }
@end @end

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
- (void)setBodyFromData:(NSData * _Nullable)data; timestamp:(uint64_t)timestamp
response:(NSURLResponse*)response
data:(NSData*)data;
- (void)setBodyFromData:(NSData* _Nullable)data;
@end @end

View File

@@ -13,30 +13,37 @@
@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
if(self = [super init]) { timestamp:(uint64_t)timestamp
response:(NSURLResponse*)response
data:(NSData*)data {
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;
} }
+ (BOOL) shouldStripReponseBodyWithResponse:(NSURLResponse *)response { + (BOOL)shouldStripReponseBodyWithResponse:(NSURLResponse*)response {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response; NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
NSString *contentType = httpResponse.allHeaderFields[@"content-type"]; NSString* contentType = httpResponse.allHeaderFields[@"content-type"];
if (!contentType) { if (!contentType) {
return NO; return NO;
} }
return [contentType containsString:@"image/"] || return [contentType containsString:@"image/"] ||
[contentType containsString:@"video/"] || [contentType containsString:@"video/"] ||
[contentType containsString:@"application/zip"]; [contentType containsString:@"application/zip"];
} }
- (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

@@ -10,60 +10,70 @@
#import <FlipperKitNetworkPlugin/SKNetworkReporter.h> #import <FlipperKitNetworkPlugin/SKNetworkReporter.h>
// Notifications posted when the record is updated // Notifications posted when the record is updated
extern NSString *const kFLEXNetworkRecorderNewTransactionNotification; extern NSString* const kFLEXNetworkRecorderNewTransactionNotification;
extern NSString *const kFLEXNetworkRecorderTransactionUpdatedNotification; extern NSString* const kFLEXNetworkRecorderTransactionUpdatedNotification;
extern NSString *const kFLEXNetworkRecorderUserInfoTransactionKey; extern NSString* const kFLEXNetworkRecorderUserInfoTransactionKey;
extern NSString *const kFLEXNetworkRecorderTransactionsClearedNotification; extern NSString* const kFLEXNetworkRecorderTransactionsClearedNotification;
@class FLEXNetworkTransaction; @class FLEXNetworkTransaction;
@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
@property (nonatomic, assign) NSUInteger responseCacheByteLimit; /// launches of the app.
@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
@property (nonatomic, assign) BOOL shouldCacheMediaResponses; /// an "image", "video", or "audio" prefix.
@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
- (NSArray<FLEXNetworkTransaction *> *)networkTransactions; /// newest first.
- (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
- (void)recordMechanism:(NSString *)mechanism forRequestID:(NSString *)requestID; /// used to make the request.
- (void)recordMechanism:(NSString*)mechanism forRequestID:(NSString*)requestID;
@end @end

View File

@@ -10,54 +10,65 @@
#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 kFLEXNetworkRecorderUserInfoTransactionKey = @"transaction"; NSString* const kFLEXNetworkRecorderTransactionUpdatedNotification =
NSString *const kFLEXNetworkRecorderTransactionsClearedNotification = @"kFLEXNetworkRecorderTransactionsClearedNotification"; @"kFLEXNetworkRecorderTransactionUpdatedNotification";
NSString* const kFLEXNetworkRecorderUserInfoTransactionKey = @"transaction";
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) dispatch_queue_t queue; @property(nonatomic, strong)
@property (nonatomic, strong) NSMutableDictionary<NSString *, NSNumber *> *identifierDict; NSMutableDictionary<NSString*, FLEXNetworkTransaction*>*
networkTransactionsForRequestIdentifiers;
@property(nonatomic, strong) dispatch_queue_t queue;
@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]
NSUInteger responseCacheLimit = [[[NSUserDefaults standardUserDefaults] objectForKey:kFLEXNetworkRecorderResponseCacheLimitDefaultsKey] unsignedIntegerValue]; objectForKey:kFLEXNetworkRecorderResponseCacheLimitDefaultsKey]
if (responseCacheLimit) { unsignedIntegerValue];
[_responseCache setTotalCostLimit:responseCacheLimit]; if (responseCacheLimit) {
} else { [_responseCache setTotalCostLimit:responseCacheLimit];
// Default to 25 MB max. The cache will purge earlier if there is memory pressure. } else {
[_responseCache setTotalCostLimit:25 * 1024 * 1024]; // Default to 25 MB max. The cache will purge earlier if there is memory
} // pressure.
_orderedTransactions = [NSMutableArray array]; [_responseCache setTotalCostLimit:25 * 1024 * 1024];
_networkTransactionsForRequestIdentifiers = [NSMutableDictionary dictionary];
// Serial queue used because we use mutable objects that are not thread safe
_queue = dispatch_queue_create("com.flex.FLEXNetworkRecorder", DISPATCH_QUEUE_SERIAL);
_identifierDict = [NSMutableDictionary dictionary];
} }
return self; _orderedTransactions = [NSMutableArray array];
_networkTransactionsForRequestIdentifiers =
[NSMutableDictionary dictionary];
// Serial queue used because we use mutable objects that are not thread safe
_queue = dispatch_queue_create(
"com.flex.FLEXNetworkRecorder", DISPATCH_QUEUE_SERIAL);
_identifierDict = [NSMutableDictionary dictionary];
}
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, ^{ defaultRecorder = [[[self class] alloc] init];
defaultRecorder = [[[self class] alloc] init]; });
}); return defaultRecorder;
return defaultRecorder;
} }
#pragma mark - Public Data Access #pragma mark - Public Data Access
@@ -66,153 +77,175 @@ 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]
[[NSUserDefaults standardUserDefaults] setObject:@(responseCacheByteLimit) forKey:kFLEXNetworkRecorderResponseCacheLimitDefaultsKey]; 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]; });
}); 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]; [self.networkTransactionsForRequestIdentifiers removeAllObjects];
[self.networkTransactionsForRequestIdentifiers removeAllObjects]; });
});
} }
#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
[self recordLoadingFinishedWithRequestID:requestID responseBody:nil]; response:redirectResponse];
} [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]
[self.delegate didObserveRequest:info]; initWithIdentifier:self.identifierDict[requestID].longLongValue
timestamp:[NSDate timestamp]
request:request
data:request.HTTPBody];
[self.delegate didObserveRequest:info];
FLEXNetworkTransaction *transaction = [FLEXNetworkTransaction new]; FLEXNetworkTransaction* transaction = [FLEXNetworkTransaction new];
transaction.requestID = requestID; transaction.requestID = requestID;
transaction.request = request; transaction.request = request;
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
transaction.transactionState = FLEXNetworkTransactionStateAwaitingResponse; forKey:requestID];
}); 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 =
if (!transaction) { self.networkTransactionsForRequestIdentifiers[requestID];
return; if (!transaction) {
} return;
transaction.response = response; }
transaction.transactionState = FLEXNetworkTransactionStateReceivingData; transaction.response = response;
transaction.latency = -[transaction.startTime timeIntervalSinceDate:responseDate]; transaction.transactionState = FLEXNetworkTransactionStateReceivingData;
}); 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 =
if (!transaction) { self.networkTransactionsForRequestIdentifiers[requestID];
return; if (!transaction) {
} return;
transaction.receivedDataLength += dataLength; }
}); transaction.receivedDataLength += 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 {
NSDate *finishedDate = [NSDate date]; NSDate* finishedDate = [NSDate date];
dispatch_async(self.queue, ^{ dispatch_async(self.queue, ^{
FLEXNetworkTransaction* transaction =
self.networkTransactionsForRequestIdentifiers[requestID];
if (!transaction) {
return;
}
transaction.transactionState = FLEXNetworkTransactionStateFinished;
transaction.duration =
-[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.delegate didObserveResponse:responseInfo];
FLEXNetworkTransaction *transaction = self.networkTransactionsForRequestIdentifiers[requestID]; BOOL shouldCache = [responseBody length] > 0;
if (!transaction) { if (!self.shouldCacheMediaResponses) {
return; NSArray<NSString*>* ignoredMIMETypePrefixes =
} @[ @"audio", @"image", @"video" ];
transaction.transactionState = FLEXNetworkTransactionStateFinished; for (NSString* ignoredPrefix in ignoredMIMETypePrefixes) {
transaction.duration = -[transaction.startTime timeIntervalSinceDate:finishedDate]; shouldCache = shouldCache &&
SKResponseInfo *responseInfo = [[SKResponseInfo alloc] initWithIndentifier:self.identifierDict[requestID].longLongValue timestamp:[NSDate timestamp] response:transaction.response data:responseBody]; ![transaction.response.MIMEType hasPrefix:ignoredPrefix];
self.identifierDict[requestID] = nil; //Clear the entry }
[self.delegate didObserveResponse:responseInfo]; }
BOOL shouldCache = [responseBody length] > 0; if (shouldCache) {
if (!self.shouldCacheMediaResponses) { [self.responseCache setObject:responseBody
NSArray<NSString *> *ignoredMIMETypePrefixes = @[ @"audio", @"image", @"video" ]; forKey:requestID
for (NSString *ignoredPrefix in ignoredMIMETypePrefixes) { cost:[responseBody length]];
shouldCache = shouldCache && ![transaction.response.MIMEType hasPrefix:ignoredPrefix]; }
} });
}
if (shouldCache) {
[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 =
if (!transaction) { self.networkTransactionsForRequestIdentifiers[requestID];
return; if (!transaction) {
} return;
}
SKResponseInfo *responseInfo = [[SKResponseInfo alloc] initWithIndentifier:self.identifierDict[requestID].longLongValue timestamp:[NSDate timestamp] response:transaction.response data: nil]; SKResponseInfo* responseInfo = [[SKResponseInfo alloc]
self.identifierDict[requestID] = nil; //Clear the entry initWithIndentifier:self.identifierDict[requestID].longLongValue
[self.delegate didObserveResponse:responseInfo]; timestamp:[NSDate timestamp]
transaction.transactionState = FLEXNetworkTransactionStateFailed; response:transaction.response
transaction.duration = -[transaction.startTime timeIntervalSinceNow]; data:nil];
transaction.error = error; self.identifierDict[requestID] = nil; // Clear the entry
}); [self.delegate didObserveResponse:responseInfo];
transaction.transactionState = FLEXNetworkTransactionStateFailed;
transaction.duration = -[transaction.startTime timeIntervalSinceNow];
transaction.error = error;
});
} }
- (void)recordMechanism:(NSString *)mechanism forRequestID:(NSString *)requestID - (void)recordMechanism:(NSString*)mechanism forRequestID:(NSString*)requestID {
{ 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.requestMechanism = mechanism; transaction.requestMechanism = mechanism;
}); });
} }
@end @end

View File

@@ -10,35 +10,37 @@
#import "UIKit/UIKit.h" #import "UIKit/UIKit.h"
typedef NS_ENUM(NSInteger, FLEXNetworkTransactionState) { typedef NS_ENUM(NSInteger, FLEXNetworkTransactionState) {
FLEXNetworkTransactionStateUnstarted, FLEXNetworkTransactionStateUnstarted,
FLEXNetworkTransactionStateAwaitingResponse, FLEXNetworkTransactionStateAwaitingResponse,
FLEXNetworkTransactionStateReceivingData, FLEXNetworkTransactionStateReceivingData,
FLEXNetworkTransactionStateFinished, FLEXNetworkTransactionStateFinished,
FLEXNetworkTransactionStateFailed FLEXNetworkTransactionStateFailed
}; };
@interface FLEXNetworkTransaction : NSObject @interface FLEXNetworkTransaction : NSObject
@property (nonatomic, copy) NSString *requestID; @property(nonatomic, copy) NSString* requestID;
@property (nonatomic, strong) NSURLRequest *request; @property(nonatomic, strong) NSURLRequest* request;
@property (nonatomic, strong) NSURLResponse *response; @property(nonatomic, strong) NSURLResponse* response;
@property (nonatomic, copy) NSString *requestMechanism; @property(nonatomic, copy) NSString* requestMechanism;
@property (nonatomic, assign) FLEXNetworkTransactionState transactionState; @property(nonatomic, assign) FLEXNetworkTransactionState transactionState;
@property (nonatomic, strong) NSError *error; @property(nonatomic, strong) NSError* error;
@property (nonatomic, strong) NSDate *startTime; @property(nonatomic, strong) NSDate* startTime;
@property (nonatomic, assign) NSTimeInterval latency; @property(nonatomic, assign) NSTimeInterval latency;
@property (nonatomic, assign) NSTimeInterval duration; @property(nonatomic, assign) NSTimeInterval duration;
@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
@property (nonatomic, strong) UIImage *responseThumbnail; /// response.
@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

@@ -9,71 +9,76 @@
@interface FLEXNetworkTransaction () @interface FLEXNetworkTransaction ()
@property (nonatomic, strong, readwrite) NSData *cachedRequestBody; @property(nonatomic, strong, readwrite) NSData* cachedRequestBody;
@end @end
@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;
} }
- (NSData *)cachedRequestBody { - (NSData*)cachedRequestBody {
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
NSInputStream *bodyStream = [self.request.HTTPBodyStream copy]; conformsToProtocol:@protocol(NSCopying)]) {
const NSUInteger bufferSize = 1024; NSInputStream* bodyStream = [self.request.HTTPBodyStream copy];
uint8_t buffer[bufferSize]; const NSUInteger bufferSize = 1024;
NSMutableData *data = [NSMutableData data]; uint8_t buffer[bufferSize];
[bodyStream open]; NSMutableData* data = [NSMutableData data];
NSInteger readBytes = 0; [bodyStream open];
do { NSInteger readBytes = 0;
readBytes = [bodyStream read:buffer maxLength:bufferSize]; do {
[data appendBytes:buffer length:readBytes]; readBytes = [bodyStream read:buffer maxLength:bufferSize];
} while (readBytes > 0); [data appendBytes:buffer length:readBytes];
[bodyStream close]; } while (readBytes > 0);
_cachedRequestBody = data; [bodyStream close];
} _cachedRequestBody = data;
} }
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:
readableString = @"Unstarted"; readableString = @"Unstarted";
break; break;
case FLEXNetworkTransactionStateAwaitingResponse: case FLEXNetworkTransactionStateAwaitingResponse:
readableString = @"Awaiting Response"; readableString = @"Awaiting Response";
break; break;
case FLEXNetworkTransactionStateReceivingData: case FLEXNetworkTransactionStateReceivingData:
readableString = @"Receiving Data"; readableString = @"Receiving Data";
break; break;
case FLEXNetworkTransactionStateFinished: case FLEXNetworkTransactionStateFinished:
readableString = @"Finished"; readableString = @"Finished";
break; break;
case FLEXNetworkTransactionStateFailed: case FLEXNetworkTransactionStateFailed:
readableString = @"Failed"; readableString = @"Failed";
break; break;
} }
return readableString; return readableString;
} }
@end @end

View File

@@ -12,13 +12,15 @@
#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)
+ (NSNumber *)random; + (NSNumber*)random;
@end @end
@@ -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,86 +7,102 @@
#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);
BOOL implementsSelector = NO; BOOL implementsSelector = NO;
for (int index = 0; index < numMethods; index++) { for (int index = 0; index < numMethods; index++) {
SEL methodSelector = method_getName(methods[index]); SEL methodSelector = method_getName(methods[index]);
if (selector == methodSelector) { if (selector == methodSelector) {
implementsSelector = YES; implementsSelector = YES;
break; break;
} }
}
free(methods);
if (!implementsSelector) {
return YES;
}
} }
return NO; free(methods);
if (!implementsSelector) {
return YES;
}
}
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 {
Method originalMethod = class_getInstanceMethod(className, originalSelector); // This method is only intended for swizzling methods that are know to exist
if (!originalMethod) { // on the class. Bail if that isn't the case.
return; Method originalMethod = class_getInstanceMethod(className, originalSelector);
} if (!originalMethod) {
return;
}
IMP implementation = imp_implementationWithBlock(block); IMP implementation = imp_implementationWithBlock(block);
class_addMethod(className, swizzledSelector, implementation, method_getTypeEncoding(originalMethod)); class_addMethod(
Method newMethod = class_getInstanceMethod(className, swizzledSelector); className,
method_exchangeImplementations(originalMethod, newMethod); swizzledSelector,
implementation,
method_getTypeEncoding(originalMethod));
Method newMethod = class_getInstanceMethod(className, swizzledSelector);
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
if ([self instanceRespondsButDoesNotImplementSelector:selector class:cls]) { forClass:(Class)cls
return; withMethodDescription:
} (struct objc_method_description)methodDescription
implementationBlock:(id)implementationBlock
undefinedBlock:(id)undefinedBlock {
if ([self instanceRespondsButDoesNotImplementSelector:selector class:cls]) {
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);
method_exchangeImplementations(oldMethod, newMethod); method_exchangeImplementations(oldMethod, newMethod);
} else { } else {
class_addMethod(cls, selector, implementation, methodDescription.types); class_addMethod(cls, selector, implementation, methodDescription.types);
} }
} }
@end @end
@implementation NSNumber (SonarUtility) @implementation NSNumber (SonarUtility)
+ (NSNumber *)random { + (NSNumber*)random {
int64_t identifier; int64_t identifier;
arc4random_buf(&identifier, sizeof(int64_t)); arc4random_buf(&identifier, sizeof(int64_t));
return @(identifier); return @(identifier);
@@ -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,12 +7,12 @@
#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;
@property (weak, nonatomic) id<SKNetworkReporterDelegate> delegate; @property(weak, nonatomic) id<SKNetworkReporterDelegate> delegate;
@end @end

View File

@@ -13,8 +13,8 @@
@implementation SKIOSNetworkAdapter @implementation SKIOSNetworkAdapter
@synthesize delegate = _delegate; @synthesize delegate = _delegate;
- (instancetype)init{ - (instancetype)init {
if (self=[super init]){ if (self = [super init]) {
_delegate = nil; _delegate = nil;
} }
return self; return self;

View File

@@ -12,7 +12,7 @@
+ (instancetype)sharedInstance; + (instancetype)sharedInstance;
+ (UIColor*)overlayColor; + (UIColor*)overlayColor;
- (void)mountInView:(UIView *)view withFrame:(CGRect)frame; - (void)mountInView:(UIView*)view withFrame:(CGRect)frame;
- (void)unmount; - (void)unmount;
@end @end

View File

@@ -9,16 +9,15 @@
#import "SKHighlightOverlay.h" #import "SKHighlightOverlay.h"
@implementation SKHighlightOverlay @implementation SKHighlightOverlay {
{ CALayer* _overlayLayer;
CALayer *_overlayLayer;
} }
+ (instancetype)sharedInstance { + (instancetype)sharedInstance {
static SKHighlightOverlay *sharedInstance = nil; static SKHighlightOverlay* sharedInstance = nil;
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{
sharedInstance = [self new]; sharedInstance = [self new];
}); });
return sharedInstance; return sharedInstance;
} }
@@ -32,12 +31,12 @@
return self; return self;
} }
- (void)mountInView:(UIView *)view withFrame:(CGRect)frame { - (void)mountInView:(UIView*)view withFrame:(CGRect)frame {
[CATransaction begin]; [CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue [CATransaction setValue:(id)kCFBooleanTrue
forKey:kCATransactionDisableActions]; forKey:kCATransactionDisableActions];
_overlayLayer.frame = frame; _overlayLayer.frame = frame;
[view.layer addSublayer: _overlayLayer]; [view.layer addSublayer:_overlayLayer];
[CATransaction commit]; [CATransaction commit];
} }
@@ -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,15 +5,15 @@
* 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
@interface FKUserDefaultsPlugin : NSObject <FlipperPlugin> @interface FKUserDefaultsPlugin : NSObject<FlipperPlugin>
- (instancetype)initWithSuiteName:(nullable NSString*)suiteName;
- (instancetype)initWithSuiteName:(nullable NSString *)suiteName;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

View File

@@ -10,15 +10,15 @@
#import <FlipperKit/FlipperResponder.h> #import <FlipperKit/FlipperResponder.h>
#import "FKUserDefaultsSwizzleUtility.h" #import "FKUserDefaultsSwizzleUtility.h"
static NSString *const kStandardUserDefaultsName = @"Standard UserDefaults"; static NSString* const kStandardUserDefaultsName = @"Standard UserDefaults";
static NSString *const kAppSuiteUserDefaultsName = @"App Suite UserDefaults"; static NSString* const kAppSuiteUserDefaultsName = @"App Suite UserDefaults";
@interface FKUserDefaultsPlugin () @interface FKUserDefaultsPlugin ()
@property (nonatomic, strong) id<FlipperConnection> flipperConnection; @property(nonatomic, strong) id<FlipperConnection> flipperConnection;
@property (nonatomic, strong) NSUserDefaults *standardUserDefaults; @property(nonatomic, strong) NSUserDefaults* standardUserDefaults;
@property (nonatomic, strong) NSUserDefaults *appSuiteUserDefaults; @property(nonatomic, strong) NSUserDefaults* appSuiteUserDefaults;
@property (nonatomic, copy) NSString *key; @property(nonatomic, copy) NSString* key;
@property (nonatomic, copy) NSString *suiteName; @property(nonatomic, copy) NSString* suiteName;
@end @end
@implementation FKUserDefaultsPlugin @implementation FKUserDefaultsPlugin
@@ -27,89 +27,106 @@ 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
__unsafe_unretained id firstArg = nil; swizzleSelector:@selector(setObject:forKey:)
__unsafe_unretained id secondArg = nil; class:[NSUserDefaults class]
[invocation getArgument:&firstArg atIndex:2]; block:^(NSInvocation* _Nonnull invocation) {
[invocation getArgument:&secondArg atIndex:3]; __unsafe_unretained id firstArg = nil;
[invocation invoke]; __unsafe_unretained id secondArg = nil;
[weakSelf userDefaults:([invocation.target isKindOfClass:[NSUserDefaults class]] ? invocation.target : nil) [invocation getArgument:&firstArg atIndex:2];
changedWithValue:firstArg [invocation getArgument:&secondArg atIndex:3];
key:secondArg]; [invocation invoke];
}]; [weakSelf userDefaults:([invocation.target
isKindOfClass:[NSUserDefaults
class]]
? invocation.target
: nil)
changedWithValue:firstArg
key:secondArg];
}];
} }
return self; return self;
} }
- (instancetype)initWithSuiteName:(NSString *)suiteName { - (instancetype)initWithSuiteName:(NSString*)suiteName {
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;
} }
- (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"
NSMutableDictionary *userDefaults = [NSMutableDictionary new]; withBlock:^(NSDictionary* params, id<FlipperResponder> responder) {
userDefaults[kStandardUserDefaultsName] = [self.standardUserDefaults dictionaryRepresentation]; NSMutableDictionary* userDefaults = [NSMutableDictionary new];
if (self.appSuiteUserDefaults) { userDefaults[kStandardUserDefaultsName] =
userDefaults[kAppSuiteUserDefaultsName] = [self.appSuiteUserDefaults dictionaryRepresentation]; [self.standardUserDefaults dictionaryRepresentation];
} if (self.appSuiteUserDefaults) {
[responder success:userDefaults]; userDefaults[kAppSuiteUserDefaultsName] =
}]; [self.appSuiteUserDefaults dictionaryRepresentation];
}
[connection receive:@"setSharedPreference" withBlock:^(NSDictionary *params , id<FlipperResponder> responder) { [responder success:userDefaults];
NSUserDefaults *sharedPreferences = [self sharedPreferencesForParams:params]; }];
NSString *preferenceName = params[@"preferenceName"];
[sharedPreferences setObject:params[@"preferenceValue"] forKey:preferenceName]; [connection receive:@"setSharedPreference"
[responder success:[sharedPreferences dictionaryRepresentation]]; withBlock:^(NSDictionary* params, id<FlipperResponder> responder) {
}]; NSUserDefaults* sharedPreferences =
[self sharedPreferencesForParams:params];
NSString* preferenceName = params[@"preferenceName"];
[sharedPreferences setObject:params[@"preferenceValue"]
forKey:preferenceName];
[responder success:[sharedPreferences dictionaryRepresentation]];
}];
} }
- (void)didDisconnect { - (void)didDisconnect {
self.flipperConnection = nil; self.flipperConnection = nil;
} }
- (NSString *)identifier { - (NSString*)identifier {
return @"Preferences"; return @"Preferences";
} }
#pragma mark - Private methods #pragma mark - Private methods
- (NSUserDefaults *)sharedPreferencesForParams:(NSDictionary *)params { - (NSUserDefaults*)sharedPreferencesForParams:(NSDictionary*)params {
NSString *const sharedPreferencesNameKey = @"sharedPreferencesName"; NSString* const sharedPreferencesNameKey = @"sharedPreferencesName";
if (![params[sharedPreferencesNameKey] isKindOfClass:[NSString class]]) { if (![params[sharedPreferencesNameKey] isKindOfClass:[NSString class]]) {
return _standardUserDefaults; return _standardUserDefaults;
} }
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
NSTimeInterval interval = [[NSDate date] timeIntervalSince1970] * 1000; changedWithValue:(id)value
NSString *intervalStr = [NSString stringWithFormat:@"%f", interval]; key:(NSString*)key {
NSMutableDictionary *params = [@{@"name":key, NSTimeInterval interval = [[NSDate date] timeIntervalSince1970] * 1000;
@"time":intervalStr NSString* intervalStr = [NSString stringWithFormat:@"%f", interval];
} mutableCopy]; NSMutableDictionary* params =
[@{@"name" : key, @"time" : intervalStr} mutableCopy];
if (!value) {
[params setObject:@"YES" forKey:@"deleted"]; if (!value) {
} else { [params setObject:@"YES" forKey:@"deleted"];
[params setObject:value forKey:@"value"]; } else {
} [params setObject:value forKey:@"value"];
}
NSString *sharedPreferencesName = (userDefaults == _standardUserDefaults
? kStandardUserDefaultsName NSString* sharedPreferencesName =
: kAppSuiteUserDefaultsName); (userDefaults == _standardUserDefaults ? kStandardUserDefaultsName
[params setObject:sharedPreferencesName forKey:@"preferences"]; : kAppSuiteUserDefaultsName);
[self.flipperConnection send:@"sharedPreferencesChange" withParams:[params copy]]; [params setObject:sharedPreferencesName forKey:@"preferences"];
[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

Some files were not shown because too many files have changed in this diff Show More