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
#import <Foundation/Foundation.h>
#import <FlipperKit/FlipperPlugin.h>
#import <Foundation/Foundation.h>
@interface FlipperKitBloksPlugin : NSObject<FlipperPlugin>
- (void)logAction:(NSString *)action
withData:(NSDictionary *)data;
- (void)logAction:(NSString*)action withData:(NSDictionary*)data;
@end

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -22,10 +22,12 @@ NSString *relativeDimension(CKRelativeDimension dimension) {
CKRelativeDimension relativeStructDimension(NSString* dimension) {
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"]) {
return CKRelativeDimension::Points([[dimension substringToIndex:([dimension length] - 2)] integerValue]);
return CKRelativeDimension::Points(
[[dimension substringToIndex:([dimension length] - 2)] integerValue]);
}
return CKRelativeDimension::Auto();
}

View File

@@ -11,11 +11,12 @@
#import <FlipperKit/FlipperPlugin.h>
#import "SKTapListener.h"
#import "SKInvalidation.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
withDescriptorMapper:(SKDescriptorMapper*)mapper;

View File

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

View File

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

View File

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

View File

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

View File

@@ -10,8 +10,7 @@
#import "SKNodeDescriptor.h"
#import <FlipperKitLayoutTextSearchable/FKTextSearchable.h>
@implementation SKNodeDescriptor
{
@implementation SKNodeDescriptor {
SKDescriptorMapper* _mapper;
}
@@ -30,11 +29,11 @@
}
- (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];
}
@@ -43,11 +42,13 @@
}
- (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 {
@throw [NSString stringWithFormat:@"need to implement %@", NSStringFromSelector(_cmd)];
@throw [NSString
stringWithFormat:@"need to implement %@", NSStringFromSelector(_cmd)];
}
- (NSDictionary<NSString*, SKNodeUpdateData>*)dataMutationsForNode:(id)node {
@@ -87,10 +88,11 @@
}
- (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
#endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -18,11 +18,15 @@ FB_LINKABLE(UICollectionView_SKInvalidation)
+ (void)enableInvalidations {
static dispatch_once_t 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(), ^{
[[SKInvalidation sharedInstance].delegate invalidateNode:self];
});

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -13,10 +13,14 @@
#import "SKBufferingPlugin.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 queue:(dispatch_queue_t)queue; //For test purposes
- (instancetype)initWithNetworkAdapter:(id<SKNetworkAdapterDelegate>)adapter
NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithNetworkAdapter:(id<SKNetworkAdapterDelegate>)adapter
queue:(dispatch_queue_t)
queue; // For test purposes
@property(strong, nonatomic) id<SKNetworkAdapterDelegate> adapter;

View File

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

View File

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

View File

@@ -15,7 +15,8 @@
- (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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -8,11 +8,14 @@
#if FB_SONARKIT_ENABLED
#pragma once
#import <memory>
#import "FlipperKitNetworkPlugin.h"
#import "SKDispatchQueue.h"
#import <memory>
@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
#endif

View File

@@ -21,10 +21,13 @@
#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.
/// High level network events are sent to the default FLEXNetworkRecorder instance which maintains the request history and caches response bodies.
/// This class swizzles NSURLConnection and NSURLSession delegate methods to
/// 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
+ (void)start;

View File

@@ -19,51 +19,61 @@ extern NSString *const kFLEXNetworkRecorderTransactionsClearedNotification;
@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;
@property(nonatomic, weak) id<SKNetworkReporterDelegate> delegate;
/// Defaults to 25 MB if never set. Values set here are presisted across launches of the app.
/// Defaults to 25 MB if never set. Values set here are presisted across
/// launches of the app.
@property(nonatomic, assign) NSUInteger responseCacheByteLimit;
/// If NO, the recorder not cache will not cache response for content types with an "image", "video", or "audio" prefix.
/// If NO, the recorder not cache will not cache response for content types with
/// an "image", "video", or "audio" prefix.
@property(nonatomic, assign) BOOL shouldCacheMediaResponses;
@property(nonatomic, copy) NSArray<NSString*>* hostBlacklist;
// Accessing recorded network activity
/// Array of FLEXNetworkTransaction objects ordered by start time with the newest first.
/// Array of FLEXNetworkTransaction objects ordered by start time with the
/// newest first.
- (NSArray<FLEXNetworkTransaction*>*)networkTransactions;
/// 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.
- (void)clearRecordedActivity;
// Recording network activity
/// 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.
- (void)recordResponseReceivedWithRequestID:(NSString *)requestID response:(NSURLResponse *)response;
- (void)recordResponseReceivedWithRequestID:(NSString*)requestID
response:(NSURLResponse*)response;
/// 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.
- (void)recordLoadingFinishedWithRequestID:(NSString *)requestID responseBody:(NSData *)responseBody;
- (void)recordLoadingFinishedWithRequestID:(NSString*)requestID
responseBody:(NSData*)responseBody;
/// 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.
/// This string can be set to anything useful about the API used to make the request.
/// Call to set the request mechanism anytime after recordRequestWillBeSent...
/// has been called. This string can be set to anything useful about the API
/// used to make the request.
- (void)recordMechanism:(NSString*)mechanism forRequestID:(NSString*)requestID;
@end

View File

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

View File

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

View File

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

View File

@@ -12,9 +12,11 @@
#import <Foundation/Foundation.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)
@@ -32,8 +34,18 @@
// Swizzling utilities
+ (SEL)swizzledSelectorForSelector:(SEL)selector;
+ (BOOL)instanceRespondsButDoesNotImplementSelector:(SEL)selector class:(Class)cls;
+ (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;
+ (BOOL)instanceRespondsButDoesNotImplementSelector:(SEL)selector
class:(Class)cls;
+ (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

View File

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

View File

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

View File

@@ -9,8 +9,7 @@
#import "SKHighlightOverlay.h"
@implementation SKHighlightOverlay
{
@implementation SKHighlightOverlay {
CALayer* _overlayLayer;
}
@@ -46,7 +45,10 @@
}
+ (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

View File

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

View File

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

View File

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

View File

@@ -11,7 +11,9 @@ NS_ASSUME_NONNULL_BEGIN
@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

View File

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