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

View File

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

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,12 +50,20 @@ 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]))
}] ];
}
- (void)setMutableData:(id)data {
@@ -55,15 +73,19 @@ FB_LINKABLE(CKCenterLayoutComponent_Sonar)
[self setValue:@(value.sizingOptions) forKey:@"_sizingOptions"];
}
- (NSDictionary<NSString *, SKNodeDataChanged> *)sonar_getDataMutationsChanged {
- (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)];
},
@"CKCenterLayoutComponent.centeringOptions.centeringX" : ^(NSNumber* value){
options.centeringOptions ^= CKCenterLayoutComponentCenteringX;
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

@@ -14,13 +14,13 @@ typedef id (^SKNodeDataChanged)(id value);
FB_LINK_REQUIRE_CATEGORY(CKComponent_Sonar)
@interface CKComponent (Sonar)
@property (assign, nonatomic) NSUInteger flipper_canBeReusedCounter;
@property(assign, nonatomic) NSUInteger flipper_canBeReusedCounter;
- (void)setMutableData:(id)data;
- (NSDictionary<NSString *, SKNodeDataChanged> *)sonar_getDataMutationsChanged;
- (NSArray<SKNamed<NSDictionary<NSString *, NSObject *> *> *> *)sonar_getData;
- (NSDictionary<NSString *, SKNodeUpdateData> *)sonar_getDataMutations;
- (NSString *)sonar_getName;
- (NSString *)sonar_getDecoration;
- (NSDictionary<NSString*, SKNodeDataChanged>*)sonar_getDataMutationsChanged;
- (NSArray<SKNamed<NSDictionary<NSString*, NSObject*>*>*>*)sonar_getData;
- (NSDictionary<NSString*, SKNodeUpdateData>*)sonar_getDataMutations;
- (NSString*)sonar_getName;
- (NSString*)sonar_getDecoration;
@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;
- (NSString*)sonar_componentNameOverride;
- (NSString*)sonar_componentDecorationOverride;
- (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;
}
@@ -66,98 +78,104 @@ static NSDictionary<NSString *, NSObject *> *AccessibilityContextDict(CKComponen
FB_LINKABLE(CKComponent_Sonar)
@implementation CKComponent (Sonar)
static FKDataStorageForLiveEditing *_dataStorage;
static NSMutableSet<NSString *> *_swizzledClasses;
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,
originalSEL,
method_getImplementation(replacement),
method_getTypeEncoding(replacement));
BOOL didAddMethod = class_addMethod(
targetClass,
originalSEL,
method_getImplementation(replacement),
method_getTypeEncoding(replacement));
if (didAddMethod) {
class_replaceMethod(targetClass,
replacementSEL,
method_getImplementation(original),
method_getTypeEncoding(original));
class_replaceMethod(
targetClass,
replacementSEL,
method_getImplementation(original),
method_getTypeEncoding(original));
} else {
method_exchangeImplementations(original, replacement);
}
}
- (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
{
static NSDictionary<NSNumber *, NSString *> *UIControlEventsEnumMap = @{
@(UIControlEventTouchDown): @"UIControlEventTouchDown",
@(UIControlEventTouchDownRepeat): @"UIControlEventTouchDownRepeat",
@(UIControlEventTouchDragInside): @"UIControlEventTouchDragInside",
@(UIControlEventTouchDragOutside): @"UIControlEventTouchDragOutside",
@(UIControlEventTouchDragEnter): @"UIControlEventTouchDragEnter",
@(UIControlEventTouchDragExit): @"UIControlEventTouchDragExit",
@(UIControlEventTouchUpInside): @"UIControlEventTouchUpInside",
@(UIControlEventTouchUpOutside): @"UIControlEventTouchUpOutside",
@(UIControlEventTouchCancel): @"UIControlEventTouchTouchCancel",
- (NSArray<SKNamed<NSDictionary<NSString*, NSObject*>*>*>*)sonar_getData {
static NSDictionary<NSNumber*, NSString*>* UIControlEventsEnumMap = @{
@(UIControlEventTouchDown) : @"UIControlEventTouchDown",
@(UIControlEventTouchDownRepeat) : @"UIControlEventTouchDownRepeat",
@(UIControlEventTouchDragInside) : @"UIControlEventTouchDragInside",
@(UIControlEventTouchDragOutside) : @"UIControlEventTouchDragOutside",
@(UIControlEventTouchDragEnter) : @"UIControlEventTouchDragEnter",
@(UIControlEventTouchDragExit) : @"UIControlEventTouchDragExit",
@(UIControlEventTouchUpInside) : @"UIControlEventTouchUpInside",
@(UIControlEventTouchUpOutside) : @"UIControlEventTouchUpOutside",
@(UIControlEventTouchCancel) : @"UIControlEventTouchTouchCancel",
@(UIControlEventValueChanged): @"UIControlEventValueChanged",
@(UIControlEventPrimaryActionTriggered): @"UIControlEventPrimaryActionTriggered",
@(UIControlEventValueChanged) : @"UIControlEventValueChanged",
@(UIControlEventPrimaryActionTriggered) :
@"UIControlEventPrimaryActionTriggered",
@(UIControlEventEditingDidBegin): @"UIControlEventEditingDidBegin",
@(UIControlEventEditingChanged): @"UIControlEventEditingChanged",
@(UIControlEventEditingDidEnd): @"UIControlEventEditingDidEnd",
@(UIControlEventEditingDidEndOnExit): @"UIControlEventEditingDidEndOnExit",
};
@(UIControlEventEditingDidBegin) : @"UIControlEventEditingDidBegin",
@(UIControlEventEditingChanged) : @"UIControlEventEditingChanged",
@(UIControlEventEditingDidEnd) : @"UIControlEventEditingDidEnd",
@(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])),
@"size": SKObject(ckcomponentSize([self size])),
}]];
[data addObject:[SKNamed newWithName:@"CKComponent"
withValue:@{
@"frame" : SKObject(self.viewContext.frame),
@"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"
withValue: @{
@"This component can be reused" :
SKObject([NSString stringWithFormat:@"%lu times", (unsigned long)canBeReusedCounter])
}]];
[data addObject:[SKNamed
newWithName:@"Convert to CKRenderComponent"
withValue:@{
@"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];
for (NSNumber* controlEvent : [UIControlEventsEnumMap allKeys]) {
NSMutableArray<NSDictionary<NSString*, NSObject*>*>* responders =
[NSMutableArray new];
for (const auto action : _actions) {
if ((action.first & [controlEvent integerValue]) == 0) {
@@ -167,20 +185,25 @@ static CK::StaticMutex _mutex = CK_MUTEX_INITIALIZER;
for (auto responder : action.second) {
auto debugTarget = _CKTypedComponentDebugInitialTarget(responder);
if (debugTarget.isBlockBaseAction()) {
[responders addObject: @{
@"identifier": SKObject(@(responder.identifier().c_str())),
@"selector": SKObject(NSStringFromSelector(responder.selector())),
}];
[responders addObject:@{
@"identifier" : SKObject(@(responder.identifier().c_str())),
@"selector" :
SKObject(NSStringFromSelector(responder.selector())),
}];
} else {
id initialTarget = debugTarget.get(self);
const CKActionInfo actionInfo = CKActionFind(responder.selector(), initialTarget);
[responders addObject: @{
@"initialTarget": SKObject(NSStringFromClass([initialTarget class])),
@"identifier": SKObject(@(responder.identifier().c_str())),
@"handler": SKObject(NSStringFromClass([actionInfo.responder class])),
@"selector": SKObject(NSStringFromSelector(responder.selector())),
}];
const CKActionInfo actionInfo =
CKActionFind(responder.selector(), initialTarget);
[responders addObject:@{
@"initialTarget" :
SKObject(NSStringFromClass([initialTarget class])),
@"identifier" : SKObject(@(responder.identifier().c_str())),
@"handler" :
SKObject(NSStringFromClass([actionInfo.responder class])),
@"selector" :
SKObject(NSStringFromSelector(responder.selector())),
}];
}
}
}
@@ -190,19 +213,23 @@ static CK::StaticMutex _mutex = CK_MUTEX_INITIALIZER;
}
}
[data addObject: [SKNamed newWithName: @"Actions" withValue: actions]];
[data addObject:[SKNamed newWithName:@"Actions" withValue:actions]];
}
}
// Only add accessibility panel if accessibilityContext is not default
CKComponentAccessibilityContext accessibilityContext = [self viewConfiguration].accessibilityContext();
CKComponentAccessibilityContext accessibilityContext =
[self viewConfiguration].accessibilityContext();
if (!AccessibilityContextIsDefault(accessibilityContext)) {
[data addObject:
[SKNamed newWithName: @"Accessibility"
withValue: @{
@"accessibilityContext": AccessibilityContextDict(accessibilityContext),
@"accessibilityEnabled": SKMutableObject(@(CK::Component::Accessibility::IsAccessibilityEnabled())),
}]];
[data addObject:[SKNamed
newWithName:@"Accessibility"
withValue:@{
@"accessibilityContext" :
AccessibilityContextDict(accessibilityContext),
@"accessibilityEnabled" : SKMutableObject(
@(CK::Component::Accessibility::
IsAccessibilityEnabled())),
}]];
}
if ([self respondsToSelector:@selector(sonar_additionalDataOverride)]) {
[data addObjectsFromArray:[(id)self sonar_additionalDataOverride]];
@@ -212,10 +239,9 @@ static CK::StaticMutex _mutex = CK_MUTEX_INITIALIZER;
}
- (void)setMutableData:(id)value {
}
- (void) setMutableDataFromStorage {
- (void)setMutableDataFromStorage {
const auto globalID = self.treeNode.nodeIdentifier;
id data = [_dataStorage dataForTreeNodeIdentifier:globalID];
if (data) {
@@ -223,32 +249,36 @@ static CK::StaticMutex _mutex = CK_MUTEX_INITIALIZER;
}
}
+ (NSString *)swizzledMethodNameForRender {
return [NSString stringWithFormat:@"sonar_render_%@", NSStringFromClass(self)];
+ (NSString*)swizzledMethodNameForRender {
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,
resultSelector,
method_getImplementation(method),
method_getTypeEncoding(method)
);
class_addMethod(
self,
resultSelector,
method_getImplementation(method),
method_getTypeEncoding(method));
return resultSelector;
}
- (CKComponent *)sonar_render:(id)state {
- (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 {
- (NSDictionary<NSString*, SKNodeDataChanged>*)sonar_getDataMutationsChanged {
return @{};
}
- (NSDictionary<NSString *, SKNodeUpdateData> *)sonar_getDataMutations {
- (NSDictionary<NSString*, SKNodeUpdateData>*)sonar_getDataMutations {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_dataStorage = [[FKDataStorageForLiveEditing alloc] init];
@@ -259,46 +289,55 @@ 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];
NSMutableDictionary *dataMutation = [[NSMutableDictionary alloc] init];
NSDictionary<NSString*, SKNodeDataChanged>* dataChanged =
[self sonar_getDataMutationsChanged];
NSMutableDictionary* dataMutation = [[NSMutableDictionary alloc] init];
[dataMutation addEntriesFromDictionary:@{
@"Accessibility.accessibilityEnabled": ^(NSNumber *value) {
CK::Component::Accessibility::SetForceAccessibilityEnabled([value boolValue]);
}
}
}
}
];
const auto globalID = self.treeNode.nodeIdentifier;
for (NSString *key in dataChanged) {
const auto block = dataChanged[key];
[dataMutation setObject:^(id value) {
id data = block(value);
[_dataStorage setData:data forTreeNodeIdentifier:globalID];
[CKComponentDebugController reflowComponentsWithTreeNodeIdentifier:globalID];
}
forKey:key];
}
return dataMutation;
}
const auto globalID = self.treeNode.nodeIdentifier;
for (NSString* key in dataChanged) {
const auto block = dataChanged[key];
[dataMutation
setObject:^(id value) {
id data = block(value);
[_dataStorage setData:data forTreeNodeIdentifier:globalID];
[CKComponentDebugController
reflowComponentsWithTreeNodeIdentifier:globalID];
}
forKey:key];
}
return dataMutation;
}
static char const kCanBeReusedKey = ' ';
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
@end
#endif

View File

@@ -18,69 +18,72 @@
FB_LINKABLE(CKFlexboxComponent_Sonar)
@implementation CKFlexboxComponent (Sonar)
static NSDictionary<NSNumber *, NSString *> *CKFlexboxDirectionEnumMap;
static NSDictionary<NSNumber*, NSString*>* CKFlexboxDirectionEnumMap;
static NSDictionary<NSNumber *, NSString *> *CKFlexboxJustifyContentEnumMap;
static NSDictionary<NSNumber*, NSString*>* CKFlexboxJustifyContentEnumMap;
static NSDictionary<NSNumber *, NSString *> *CKFlexboxAlignItemsEnumMap;
static NSDictionary<NSNumber*, NSString*>* CKFlexboxAlignItemsEnumMap;
static NSDictionary<NSNumber *, NSString *> *CKFlexboxAlignContentEnumMap;
static NSDictionary<NSNumber*, NSString*>* CKFlexboxAlignContentEnumMap;
static NSDictionary<NSNumber *, NSString *> *CKFlexboxWrapEnumMap;
static NSDictionary<NSNumber*, NSString*>* CKFlexboxWrapEnumMap;
+ (void)initialize
{
+ (void)initialize {
CKFlexboxDirectionEnumMap = @{
@(CKFlexboxDirectionColumn): @"column",
@(CKFlexboxDirectionRow): @"row",
@(CKFlexboxDirectionColumnReverse): @"column-reverse",
@(CKFlexboxDirectionRowReverse): @"row-reverse",
};
@(CKFlexboxDirectionColumn) : @"column",
@(CKFlexboxDirectionRow) : @"row",
@(CKFlexboxDirectionColumnReverse) : @"column-reverse",
@(CKFlexboxDirectionRowReverse) : @"row-reverse",
};
CKFlexboxJustifyContentEnumMap = @{
@(CKFlexboxJustifyContentStart): @"start",
@(CKFlexboxJustifyContentCenter): @"center",
@(CKFlexboxJustifyContentEnd): @"end",
@(CKFlexboxJustifyContentSpaceBetween): @"space-between",
@(CKFlexboxJustifyContentSpaceAround): @"space-around",
};
@(CKFlexboxJustifyContentStart) : @"start",
@(CKFlexboxJustifyContentCenter) : @"center",
@(CKFlexboxJustifyContentEnd) : @"end",
@(CKFlexboxJustifyContentSpaceBetween) : @"space-between",
@(CKFlexboxJustifyContentSpaceAround) : @"space-around",
};
CKFlexboxAlignItemsEnumMap = @{
@(CKFlexboxAlignItemsStart): @"start",
@(CKFlexboxAlignItemsEnd): @"end",
@(CKFlexboxAlignItemsCenter): @"center",
@(CKFlexboxAlignItemsBaseline): @"baseline",
@(CKFlexboxAlignItemsStretch): @"stretch",
};
@(CKFlexboxAlignItemsStart) : @"start",
@(CKFlexboxAlignItemsEnd) : @"end",
@(CKFlexboxAlignItemsCenter) : @"center",
@(CKFlexboxAlignItemsBaseline) : @"baseline",
@(CKFlexboxAlignItemsStretch) : @"stretch",
};
CKFlexboxAlignContentEnumMap = @{
@(CKFlexboxAlignContentStart): @"start",
@(CKFlexboxAlignContentEnd): @"end",
@(CKFlexboxAlignContentCenter): @"center",
@(CKFlexboxAlignContentSpaceBetween): @"space-between",
@(CKFlexboxAlignContentSpaceAround): @"space-around",
@(CKFlexboxAlignContentStretch): @"stretch",
};
@(CKFlexboxAlignContentStart) : @"start",
@(CKFlexboxAlignContentEnd) : @"end",
@(CKFlexboxAlignContentCenter) : @"center",
@(CKFlexboxAlignContentSpaceBetween) : @"space-between",
@(CKFlexboxAlignContentSpaceAround) : @"space-around",
@(CKFlexboxAlignContentStretch) : @"stretch",
};
CKFlexboxWrapEnumMap = @{
@(CKFlexboxWrapWrap): @"wrap",
@(CKFlexboxWrapNoWrap): @"no-wrap",
@(CKFlexboxWrapWrapReverse): @"wrap-reverse",
};
@(CKFlexboxWrapWrap) : @"wrap",
@(CKFlexboxWrapNoWrap) : @"no-wrap",
@(CKFlexboxWrapWrapReverse) : @"wrap-reverse",
};
}
- (NSArray<SKNamed<NSDictionary<NSString *, NSObject *> *> *> *)sonar_additionalDataOverride
{
- (NSArray<SKNamed<NSDictionary<NSString*, NSObject*>*>*>*)
sonar_additionalDataOverride {
CKFlexboxComponentStyle style;
[[self valueForKey: @"_style"] getValue: &style];
[[self valueForKey:@"_style"] getValue:&style];
return @[[SKNamed
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)]),
@"wrap": SKMutableObject(CKFlexboxWrapEnumMap[@(style.wrap)]),
@"padding": SKMutableObject(flexboxRect(style.padding)),
}]];
return @[ [SKNamed
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)]),
@"wrap" : SKMutableObject(CKFlexboxWrapEnumMap[@(style.wrap)]),
@"padding" : SKMutableObject(flexboxRect(style.padding)),
}] ];
}
- (void)setMutableData:(id)data {
@@ -89,14 +92,14 @@ static NSDictionary<NSNumber *, NSString *> *CKFlexboxWrapEnumMap;
[self setValue:data forKey:@"_style"];
}
- (NSDictionary<NSString *, SKNodeDataChanged> *)sonar_getDataMutationsChanged {
- (NSDictionary<NSString*, SKNodeDataChanged>*)sonar_getDataMutationsChanged {
__block CKFlexboxComponentStyle style;
[[self valueForKey:@"_style"] getValue: &style];
return @{
@"CKFlexboxComponent.spacing": ^(NSNumber *value) {
style.spacing = value.floatValue;
return [NSValue value:&style withObjCType:@encode(CKFlexboxComponentStyle)];
},
[[self valueForKey:@"_style"] getValue:&style];
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,22 +17,27 @@
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 {
[self setValue:data forKey:@"_insets"];
}
- (NSDictionary<NSString *, SKNodeDataChanged> *)sonar_getDataMutationsChanged {
__block UIEdgeInsets insets = [[self valueForKey:@"_insets"] UIEdgeInsetsValue];
return @{
@"CKInsetComponent.insets.bottom": ^(NSNumber *value) {
insets.bottom = value.floatValue;
return [NSValue valueWithUIEdgeInsets:insets];
},
- (NSDictionary<NSString*, SKNodeDataChanged>*)sonar_getDataMutationsChanged {
__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,23 +17,28 @@
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 {
[self setValue:data forKey:@"_ratio"];
}
- (NSDictionary<NSString *, SKNodeDataChanged> *)sonar_getDataMutationsChanged {
return @{
@"CKRatioLayoutComponent.ratio": ^(NSNumber *value) {
CGFloat ratio = [(NSNumber *)[self valueForKey:@"_ratio"] floatValue];
ratio = value.floatValue;
return [NSNumber numberWithFloat:ratio];
},
};
- (NSDictionary<NSString*, SKNodeDataChanged>*)sonar_getDataMutationsChanged {
return @{@"CKRatioLayoutComponent.ratio" : ^(NSNumber* value){
CGFloat ratio = [(NSNumber*)[self valueForKey:@"_ratio"] floatValue];
ratio = value.floatValue;
return [NSNumber numberWithFloat:ratio];
}
,
}
;
}
@end

View File

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

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

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

View File

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

View File

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

View File

@@ -14,17 +14,18 @@
@interface SKComponentLayoutWrapper : NSObject
@property (nonatomic, weak, readonly) CKComponent *component;
@property (nonatomic, readonly) NSString *identifier;
@property (nonatomic, readonly) CGSize size;
@property (nonatomic, readonly) CGPoint position;
@property (nonatomic, readonly) std::vector<SKComponentLayoutWrapper *> children;
@property (nonatomic, weak, readonly) id<CKInspectableView> rootNode;
@property(nonatomic, weak, readonly) CKComponent* component;
@property(nonatomic, readonly) NSString* identifier;
@property(nonatomic, readonly) CGSize size;
@property(nonatomic, readonly) CGPoint position;
@property(nonatomic, readonly) std::vector<SKComponentLayoutWrapper*> children;
@property(nonatomic, weak, readonly) id<CKInspectableView> rootNode;
// Null for layouts which are not direct children of a CKFlexboxComponent
@property (nonatomic, readonly) BOOL isFlexboxChild;
@property (nonatomic, readonly) CKFlexboxComponentChild flexboxChild;
@property(nonatomic, readonly) BOOL isFlexboxChild;
@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);
unsigned char* pComponent = (unsigned char*)(__bridge void*)parent;
auto children =
(std::vector<CKFlexboxComponentChild>*)(pComponent + offset);
if (children) {
for (auto it = children->begin(); it != children->end(); it++) {
@@ -47,47 +51,59 @@ 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);
CKComponent* component = (CKComponent*)layout.component;
CKComponentReuseWrapper* reuseWrapper =
CKAnalyticsListenerHelpers::GetReusedNodes(component);
// Create a new layout wrapper.
SKComponentLayoutWrapper *const wrapper =
[[SKComponentLayoutWrapper alloc] initWithLayout:layout
position:CGPointMake(0, 0)
parentKey:[NSString stringWithFormat: @"%@%d.", parentKey, component.treeNode.nodeIdentifier]
reuseWrapper:reuseWrapper
rootNode: root];
SKComponentLayoutWrapper* const wrapper = [[SKComponentLayoutWrapper alloc]
initWithLayout:layout
position:CGPointMake(0, 0)
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;
}
- (instancetype)initWithLayout:(const CKComponentLayout &)layout
- (instancetype)initWithLayout:(const CKComponentLayout&)layout
position:(CGPoint)position
parentKey:(NSString *)parentKey
reuseWrapper:(CKComponentReuseWrapper *)reuseWrapper
rootNode:(id<CKInspectableView>)node
{
parentKey:(NSString*)parentKey
reuseWrapper:(CKComponentReuseWrapper*)reuseWrapper
rootNode:(id<CKInspectableView>)node {
if (self = [super init]) {
_rootNode = node;
_component = (CKComponent *)layout.component;
_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;
}
@@ -95,18 +111,22 @@ static CKFlexboxComponentChild findFlexboxLayoutParams(CKComponent *parent, CKCo
if (layout.children != nullptr) {
int index = 0;
for (const auto &child : *layout.children) {
for (const auto& child : *layout.children) {
if (child.layout.component == nil) {
continue; // nil children are allowed, ignore them
}
SKComponentLayoutWrapper *childWrapper = [[SKComponentLayoutWrapper alloc] initWithLayout:child.layout
position:child.position
parentKey:[_identifier stringByAppendingFormat:@"[%d].", index++]
reuseWrapper:reuseWrapper
rootNode:node
];
childWrapper->_isFlexboxChild = [_component isKindOfClass:[CKFlexboxComponent class]];
childWrapper->_flexboxChild = findFlexboxLayoutParams(_component, (CKComponent *)child.layout.component);
SKComponentLayoutWrapper* childWrapper =
[[SKComponentLayoutWrapper alloc]
initWithLayout:child.layout
position:child.position
parentKey:[_identifier
stringByAppendingFormat:@"[%d].", index++]
reuseWrapper:reuseWrapper
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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

@@ -15,8 +15,8 @@ typedef void (^SKNodeUpdateData)(id value);
/**
A SKNodeDescriptor is an object which know how to expose an Object of type T
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,34 +27,35 @@ 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;
- (instancetype)initWithDescriptorMapper:(SKDescriptorMapper*)mapper;
/**
Gets the node-descriptor registered for a specific class.
*/
- (SKNodeDescriptor *)descriptorForClass:(Class)cls;
- (SKNodeDescriptor*)descriptorForClass:(Class)cls;
/**
A globally unique ID used to identify a node in the hierarchy. This is used
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;
- (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;
- (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;
- (NSString*)nameForNode:(T)node;
/**
The number of children this node exposes in the layout hierarchy.
@@ -67,29 +68,30 @@ typedef void (^SKNodeUpdateData)(id value);
- (id)childForNode:(T)node atIndex:(NSUInteger)index;
/**
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;
- (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;
- (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;
- (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;
@@ -98,7 +100,7 @@ typedef void (^SKNodeUpdateData)(id value);
one of the children of the node, or finish the hit testing on this
node.
*/
- (void)hitTest:(SKTouch *)point forNode:(T)node;
- (void)hitTest:(SKTouch*)point forNode:(T)node;
/**
Invalidate a specific node. This is called once a node is removed or added
@@ -110,12 +112,12 @@ typedef void (^SKNodeUpdateData)(id value);
The decoration for this node. Valid values are defined in the Sonar
applictation.
*/
- (NSString *)decorationForNode:(T)node;
- (NSString*)decorationForNode:(T)node;
/**
Whether the node matches the given query.
Used for layout search.
*/
- (BOOL)matchesQuery:(NSString *)query forNode:(T)node;
- (BOOL)matchesQuery:(NSString*)query forNode:(T)node;
@end

View File

@@ -10,87 +10,89 @@
#import "SKNodeDescriptor.h"
#import <FlipperKitLayoutTextSearchable/FKTextSearchable.h>
@implementation SKNodeDescriptor
{
SKDescriptorMapper *_mapper;
@implementation SKNodeDescriptor {
SKDescriptorMapper* _mapper;
}
- (void)setUp {
}
- (instancetype)initWithDescriptorMapper:(SKDescriptorMapper *)mapper {
- (instancetype)initWithDescriptorMapper:(SKDescriptorMapper*)mapper {
if (self = [super init]) {
_mapper = mapper;
}
return self;
}
- (SKNodeDescriptor *)descriptorForClass:(Class)cls {
return [_mapper descriptorForClass: cls];
- (SKNodeDescriptor*)descriptorForClass:(Class)cls {
return [_mapper descriptorForClass:cls];
}
- (NSString *)identifierForNode:(id)node {
@throw [NSString stringWithFormat:@"need to implement %@", NSStringFromSelector(_cmd)];
- (NSString*)identifierForNode:(id)node {
@throw [NSString
stringWithFormat:@"need to implement %@", NSStringFromSelector(_cmd)];
}
- (NSString *)identifierForInvalidation:(id)node
{
- (NSString*)identifierForInvalidation:(id)node {
return [self identifierForNode:node];
}
- (NSString *)nameForNode:(id)node {
- (NSString*)nameForNode:(id)node {
return NSStringFromClass([node class]);
}
- (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 {
- (NSDictionary<NSString*, SKNodeUpdateData>*)dataMutationsForNode:(id)node {
return @{};
}
- (NSArray<SKNamed<NSDictionary *> *> *)dataForNode:(id)node {
- (NSArray<SKNamed<NSDictionary*>*>*)dataForNode:(id)node {
return @[];
}
- (NSArray<SKNamed<NSString *> *> *)attributesForNode:(id)node {
- (NSArray<SKNamed<NSString*>*>*)attributesForNode:(id)node {
return @[];
}
- (void)setHighlighted:(BOOL)highlighted forNode:(id)node {
}
- (void)hitTest:(SKTouch *)point forNode:(id)node {
- (void)hitTest:(SKTouch*)point forNode:(id)node {
}
- (void)invalidateNode:(id)node {
}
- (NSString *)decorationForNode:(id)node {
- (NSString*)decorationForNode:(id)node {
return @"";
}
- (BOOL)matchesQuery:(NSString *)query forNode:(id)node {
NSString *name = [self nameForNode: node];
NSString *text = nil;
if ([node conformsToProtocol:@protocol(FKTextSearchable)]) {
text = [node searchableText];
}
return [self string:name contains:query] ||
[self string:[self identifierForNode: node] contains: query] ||
[self string:text contains:query];
- (BOOL)matchesQuery:(NSString*)query forNode:(id)node {
NSString* name = [self nameForNode:node];
NSString* text = nil;
if ([node conformsToProtocol:@protocol(FKTextSearchable)]) {
text = [node searchableText];
}
return [self string:name contains:query] ||
[self string:[self identifierForNode:node] contains:query] ||
[self string:text contains:query];
}
- (BOOL)string:(NSString *)string contains:(NSString *)substring {
return string != nil && substring != nil && [string rangeOfString: substring options: NSCaseInsensitiveSearch].location != NSNotFound;
- (BOOL)string:(NSString*)string contains:(NSString*)substring {
return string != nil && substring != nil &&
[string rangeOfString:substring options:NSCaseInsensitiveSearch]
.location != NSNotFound;
}
@end
#endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

@@ -7,25 +7,31 @@
#import <Foundation/Foundation.h>
#define APPLY_ENUM_TO_YOGA_PROPERTY(varName, enumName) \
^(NSString *newValue) { \
NSNumber *varName = [[enumName##EnumMap allKeysForObject:newValue] lastObject]; \
if (varName == nil) { return; } \
node.yoga.varName = (enumName)[varName unsignedIntegerValue]; \
}
#define APPLY_ENUM_TO_YOGA_PROPERTY(varName, enumName) \
^(NSString * newValue) { \
NSNumber* varName = \
[[enumName##EnumMap allKeysForObject:newValue] lastObject]; \
if (varName == nil) { \
return; \
} \
node.yoga.varName = (enumName)[varName unsignedIntegerValue]; \
}
#define APPLY_VALUE_TO_YGVALUE(varName) \
^(NSNumber *value) { \
YGValue newValue = node.yoga.varName; \
newValue.value = [value floatValue]; \
node.yoga.varName = newValue; \
}
#define APPLY_VALUE_TO_YGVALUE(varName) \
^(NSNumber * value) { \
YGValue newValue = node.yoga.varName; \
newValue.value = [value floatValue]; \
node.yoga.varName = newValue; \
}
#define APPLY_UNIT_TO_YGVALUE(varName, enumName) \
^(NSString *value) { \
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; \
}
#define APPLY_UNIT_TO_YGVALUE(varName, enumName) \
^(NSString * value) { \
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,8 @@
#import <UIKit/UIKit.h>
@protocol FKTextSearchable <NSObject>
@protocol FKTextSearchable<NSObject>
- (NSString *)searchableText;
- (NSString*)searchableText;
@end

View File

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

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

View File

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

View File

@@ -9,12 +9,11 @@
@implementation TestNode
- (instancetype)initWithName:(NSString *)name {
return [self initWithName: name
withFrame: CGRectZero];
- (instancetype)initWithName:(NSString*)name {
return [self initWithName:name withFrame:CGRectZero];
}
- (instancetype)initWithName:(NSString *)name withFrame:(CGRect)frame {
- (instancetype)initWithName:(NSString*)name withFrame:(CGRect)frame {
if (self = [super init]) {
_nodeName = name;
_frame = frame;

View File

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

View File

@@ -9,27 +9,27 @@
@implementation TestNodeDescriptor
- (NSString *)identifierForNode:(TestNode *)node {
- (NSString*)identifierForNode:(TestNode*)node {
return node.nodeName;
}
- (NSUInteger)childCountForNode:(TestNode *)node {
- (NSUInteger)childCountForNode:(TestNode*)node {
return [node.children count];
}
- (id)childForNode:(TestNode *)node atIndex:(NSUInteger)index {
return [node.children objectAtIndex: index];
- (id)childForNode:(TestNode*)node atIndex:(NSUInteger)index {
return [node.children objectAtIndex:index];
}
- (void)setHighlighted:(BOOL)highlighted forNode:(TestNode *)node {
- (void)setHighlighted:(BOOL)highlighted forNode:(TestNode*)node {
node.highlighted = highlighted;
}
- (void)hitTest:(SKTouch *)touch forNode:(TestNode *)node {
- (void)hitTest:(SKTouch*)touch forNode:(TestNode*)node {
NSUInteger index = [node.children count] - 1;
for (TestNode *childNode in [node.children reverseObjectEnumerator]) {
if ([touch containedIn: childNode.frame]) {
[touch continueWithChildIndex: index withOffset: node.frame.origin];
for (TestNode* childNode in [node.children reverseObjectEnumerator]) {
if ([touch containedIn:childNode.frame]) {
[touch continueWithChildIndex:index withOffset:node.frame.origin];
return;
}
@@ -39,12 +39,13 @@
[touch finish];
}
- (NSDictionary<NSString *, SKNodeUpdateData> *)dataMutationsForNode:(TestNode *)node {
return @{
@"TestNode.name": ^(NSString *newName) {
node.nodeName = newName;
}
};
- (NSDictionary<NSString*, SKNodeUpdateData>*)dataMutationsForNode:
(TestNode*)node {
return @{@"TestNode.name" : ^(NSString* newName){
node.nodeName = newName;
}
}
;
}
@end

View File

@@ -13,12 +13,16 @@
#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;
@property(strong, nonatomic) id<SKNetworkAdapterDelegate> adapter;
@end

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

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

@@ -12,31 +12,28 @@
#import <dispatch/dispatch.h>
namespace facebook {
namespace flipper {
class DispatchQueue
{
public:
virtual void async(dispatch_block_t block) = 0;
virtual ~DispatchQueue() { }
};
namespace flipper {
class DispatchQueue {
public:
virtual void async(dispatch_block_t block) = 0;
virtual ~DispatchQueue() {}
};
class GCDQueue: public DispatchQueue
{
public:
GCDQueue(dispatch_queue_t underlyingQueue)
:_underlyingQueue(underlyingQueue) { }
class GCDQueue : public DispatchQueue {
public:
GCDQueue(dispatch_queue_t underlyingQueue)
: _underlyingQueue(underlyingQueue) {}
void async(dispatch_block_t block) override
{
dispatch_async(_underlyingQueue, block);
}
virtual ~GCDQueue() { }
private:
dispatch_queue_t _underlyingQueue;
};
void async(dispatch_block_t block) override {
dispatch_async(_underlyingQueue, block);
}
}
virtual ~GCDQueue() {}
private:
dispatch_queue_t _underlyingQueue;
};
} // namespace flipper
} // namespace facebook
#endif

View File

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

View File

@@ -7,13 +7,16 @@
#import <Foundation/Foundation.h>
@interface SKRequestInfo: NSObject
@interface SKRequestInfo : NSObject
@property(assign, readwrite) int64_t identifier;
@property(assign, readwrite) uint64_t timestamp;
@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;
- (void)setBodyFromData:(NSData * _Nullable)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,21 +13,23 @@
@synthesize request = _request;
@synthesize body = _body;
- (instancetype)initWithIdentifier:(int64_t)identifier timestamp:(uint64_t)timestamp request:(NSURLRequest *)request data:(NSData *)data{
if (self = [super init]){
- (instancetype)initWithIdentifier:(int64_t)identifier
timestamp:(uint64_t)timestamp
request:(NSURLRequest*)request
data:(NSData*)data {
if (self = [super init]) {
_identifier = identifier;
_timestamp = timestamp;
_request = request;
_body = data ? [data base64EncodedStringWithOptions: 0]
: [request.HTTPBody base64EncodedStringWithOptions: 0];
_body = data ? [data base64EncodedStringWithOptions:0]
: [request.HTTPBody base64EncodedStringWithOptions:0];
}
return self;
}
- (void)setBodyFromData:(NSData * _Nullable)data {
self.body = data ? [data base64EncodedStringWithOptions: 0]
: [self.request.HTTPBody base64EncodedStringWithOptions: 0];
- (void)setBodyFromData:(NSData* _Nullable)data {
self.body = data ? [data base64EncodedStringWithOptions:0]
: [self.request.HTTPBody base64EncodedStringWithOptions:0];
}
@end

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;
- (void)setBodyFromData:(NSData * _Nullable)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,30 +13,37 @@
@synthesize response = _response;
@synthesize body = _body;
- (instancetype)initWithIndentifier:(int64_t)identifier timestamp:(uint64_t)timestamp response:(NSURLResponse *)response data:(NSData *)data {
if(self = [super init]) {
- (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;
}
+ (BOOL) shouldStripReponseBodyWithResponse:(NSURLResponse *)response {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
NSString *contentType = httpResponse.allHeaderFields[@"content-type"];
+ (BOOL)shouldStripReponseBodyWithResponse:(NSURLResponse*)response {
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
NSString* contentType = httpResponse.allHeaderFields[@"content-type"];
if (!contentType) {
return NO;
}
return [contentType containsString:@"image/"] ||
[contentType containsString:@"video/"] ||
[contentType containsString:@"application/zip"];
[contentType containsString:@"video/"] ||
[contentType containsString:@"application/zip"];
}
- (void)setBodyFromData:(NSData *_Nullable)data {
self.body = [SKResponseInfo shouldStripReponseBodyWithResponse:self.response] ? nil : [data base64EncodedStringWithOptions: 0];
- (void)setBodyFromData:(NSData* _Nullable)data {
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;
@interface FlipperKitNetworkPlugin (CPPInitialization)
- (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

@@ -10,60 +10,70 @@
#import <FlipperKitNetworkPlugin/SKNetworkReporter.h>
// Notifications posted when the record is updated
extern NSString *const kFLEXNetworkRecorderNewTransactionNotification;
extern NSString *const kFLEXNetworkRecorderTransactionUpdatedNotification;
extern NSString *const kFLEXNetworkRecorderUserInfoTransactionKey;
extern NSString *const kFLEXNetworkRecorderTransactionsClearedNotification;
extern NSString* const kFLEXNetworkRecorderNewTransactionNotification;
extern NSString* const kFLEXNetworkRecorderTransactionUpdatedNotification;
extern NSString* const kFLEXNetworkRecorderUserInfoTransactionKey;
extern NSString* const kFLEXNetworkRecorderTransactionsClearedNotification;
@class FLEXNetworkTransaction;
@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;
@property(nonatomic, weak) id<SKNetworkReporterDelegate> delegate;
/// Defaults to 25 MB if never set. Values set here are presisted across launches of the app.
@property (nonatomic, assign) NSUInteger responseCacheByteLimit;
/// 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.
@property (nonatomic, assign) BOOL shouldCacheMediaResponses;
@property (nonatomic, copy) NSArray<NSString *> *hostBlacklist;
/// 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.
- (NSArray<FLEXNetworkTransaction *> *)networkTransactions;
/// 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.
- (void)recordMechanism:(NSString *)mechanism forRequestID:(NSString *)requestID;
/// 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,54 +10,65 @@
#import "FLEXNetworkTransaction.h"
#import "FLEXUtility.h"
NSString *const kFLEXNetworkRecorderNewTransactionNotification = @"kFLEXNetworkRecorderNewTransactionNotification";
NSString *const kFLEXNetworkRecorderTransactionUpdatedNotification = @"kFLEXNetworkRecorderTransactionUpdatedNotification";
NSString *const kFLEXNetworkRecorderUserInfoTransactionKey = @"transaction";
NSString *const kFLEXNetworkRecorderTransactionsClearedNotification = @"kFLEXNetworkRecorderTransactionsClearedNotification";
NSString* const kFLEXNetworkRecorderNewTransactionNotification =
@"kFLEXNetworkRecorderNewTransactionNotification";
NSString* const kFLEXNetworkRecorderTransactionUpdatedNotification =
@"kFLEXNetworkRecorderTransactionUpdatedNotification";
NSString* const kFLEXNetworkRecorderUserInfoTransactionKey = @"transaction";
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) dispatch_queue_t queue;
@property (nonatomic, strong) NSMutableDictionary<NSString *, NSNumber *> *identifierDict;
@property(nonatomic, strong) NSCache* responseCache;
@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;
@end
@implementation FLEXNetworkRecorder
- (instancetype)init
{
self = [super init];
if (self) {
_responseCache = [NSCache new];
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.
[_responseCache setTotalCostLimit:25 * 1024 * 1024];
}
_orderedTransactions = [NSMutableArray array];
_networkTransactionsForRequestIdentifiers = [NSMutableDictionary dictionary];
// Serial queue used because we use mutable objects that are not thread safe
_queue = dispatch_queue_create("com.flex.FLEXNetworkRecorder", DISPATCH_QUEUE_SERIAL);
_identifierDict = [NSMutableDictionary dictionary];
- (instancetype)init {
self = [super init];
if (self) {
_responseCache = [NSCache new];
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.
[_responseCache setTotalCostLimit:25 * 1024 * 1024];
}
return self;
_orderedTransactions = [NSMutableArray array];
_networkTransactionsForRequestIdentifiers =
[NSMutableDictionary dictionary];
// Serial queue used because we use mutable objects that are not thread safe
_queue = dispatch_queue_create(
"com.flex.FLEXNetworkRecorder", DISPATCH_QUEUE_SERIAL);
_identifierDict = [NSMutableDictionary dictionary];
}
return self;
}
+ (instancetype)defaultRecorder
{
static FLEXNetworkRecorder *defaultRecorder = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
defaultRecorder = [[[self class] alloc] init];
});
return defaultRecorder;
+ (instancetype)defaultRecorder {
static FLEXNetworkRecorder* defaultRecorder = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
defaultRecorder = [[[self class] alloc] init];
});
return defaultRecorder;
}
#pragma mark - Public Data Access
@@ -66,153 +77,175 @@ NSString *const kFLEXNetworkRecorderResponseCacheLimitDefaultsKey = @"com.flex.r
_delegate = delegate;
}
- (NSUInteger)responseCacheByteLimit
{
return [self.responseCache totalCostLimit];
- (NSUInteger)responseCacheByteLimit {
return [self.responseCache totalCostLimit];
}
- (void)setResponseCacheByteLimit:(NSUInteger)responseCacheByteLimit
{
[self.responseCache setTotalCostLimit:responseCacheByteLimit];
[[NSUserDefaults standardUserDefaults] setObject:@(responseCacheByteLimit) forKey:kFLEXNetworkRecorderResponseCacheLimitDefaultsKey];
- (void)setResponseCacheByteLimit:(NSUInteger)responseCacheByteLimit {
[self.responseCache setTotalCostLimit:responseCacheByteLimit];
[[NSUserDefaults standardUserDefaults]
setObject:@(responseCacheByteLimit)
forKey:kFLEXNetworkRecorderResponseCacheLimitDefaultsKey];
}
- (NSArray<FLEXNetworkTransaction *> *)networkTransactions
{
__block NSArray<FLEXNetworkTransaction *> *transactions = nil;
dispatch_sync(self.queue, ^{
transactions = [self.orderedTransactions copy];
});
return transactions;
- (NSArray<FLEXNetworkTransaction*>*)networkTransactions {
__block NSArray<FLEXNetworkTransaction*>* transactions = nil;
dispatch_sync(self.queue, ^{
transactions = [self.orderedTransactions copy];
});
return transactions;
}
- (NSData *)cachedResponseBodyForTransaction:(FLEXNetworkTransaction *)transaction
{
return [self.responseCache objectForKey:transaction.requestID];
- (NSData*)cachedResponseBodyForTransaction:
(FLEXNetworkTransaction*)transaction {
return [self.responseCache objectForKey:transaction.requestID];
}
- (void)clearRecordedActivity
{
dispatch_async(self.queue, ^{
[self.responseCache removeAllObjects];
[self.orderedTransactions removeAllObjects];
[self.networkTransactionsForRequestIdentifiers removeAllObjects];
});
- (void)clearRecordedActivity {
dispatch_async(self.queue, ^{
[self.responseCache removeAllObjects];
[self.orderedTransactions removeAllObjects];
[self.networkTransactionsForRequestIdentifiers removeAllObjects];
});
}
#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];
NSDate* startDate = [NSDate date];
if (redirectResponse) {
[self recordResponseReceivedWithRequestID:requestID response:redirectResponse];
[self recordLoadingFinishedWithRequestID:requestID responseBody:nil];
}
if (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];
[self.delegate didObserveRequest:info];
dispatch_async(self.queue, ^{
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];
transaction.requestID = requestID;
transaction.request = request;
transaction.startTime = startDate;
FLEXNetworkTransaction* transaction = [FLEXNetworkTransaction new];
transaction.requestID = requestID;
transaction.request = request;
transaction.startTime = startDate;
[self.orderedTransactions insertObject:transaction atIndex:0];
[self.networkTransactionsForRequestIdentifiers setObject:transaction forKey:requestID];
transaction.transactionState = FLEXNetworkTransactionStateAwaitingResponse;
});
[self.orderedTransactions insertObject:transaction atIndex:0];
[self.networkTransactionsForRequestIdentifiers setObject:transaction
forKey:requestID];
transaction.transactionState = FLEXNetworkTransactionStateAwaitingResponse;
});
}
/// Call when HTTP response is available.
- (void)recordResponseReceivedWithRequestID:(NSString *)requestID response:(NSURLResponse *)response
{
NSDate *responseDate = [NSDate date];
- (void)recordResponseReceivedWithRequestID:(NSString*)requestID
response:(NSURLResponse*)response {
NSDate* responseDate = [NSDate date];
dispatch_async(self.queue, ^{
FLEXNetworkTransaction *transaction = self.networkTransactionsForRequestIdentifiers[requestID];
if (!transaction) {
return;
}
transaction.response = response;
transaction.transactionState = FLEXNetworkTransactionStateReceivingData;
transaction.latency = -[transaction.startTime timeIntervalSinceDate:responseDate];
});
dispatch_async(self.queue, ^{
FLEXNetworkTransaction* transaction =
self.networkTransactionsForRequestIdentifiers[requestID];
if (!transaction) {
return;
}
transaction.response = response;
transaction.transactionState = FLEXNetworkTransactionStateReceivingData;
transaction.latency =
-[transaction.startTime timeIntervalSinceDate:responseDate];
});
}
/// Call when data chunk is received over the network.
- (void)recordDataReceivedWithRequestID:(NSString *)requestID dataLength:(int64_t)dataLength
{
dispatch_async(self.queue, ^{
FLEXNetworkTransaction *transaction = self.networkTransactionsForRequestIdentifiers[requestID];
if (!transaction) {
return;
}
transaction.receivedDataLength += dataLength;
});
- (void)recordDataReceivedWithRequestID:(NSString*)requestID
dataLength:(int64_t)dataLength {
dispatch_async(self.queue, ^{
FLEXNetworkTransaction* transaction =
self.networkTransactionsForRequestIdentifiers[requestID];
if (!transaction) {
return;
}
transaction.receivedDataLength += dataLength;
});
}
/// Call when HTTP request has finished loading.
- (void)recordLoadingFinishedWithRequestID:(NSString *)requestID responseBody:(NSData *)responseBody
{
NSDate *finishedDate = [NSDate date];
dispatch_async(self.queue, ^{
- (void)recordLoadingFinishedWithRequestID:(NSString*)requestID
responseBody:(NSData*)responseBody {
NSDate* finishedDate = [NSDate date];
dispatch_async(self.queue, ^{
FLEXNetworkTransaction* transaction =
self.networkTransactionsForRequestIdentifiers[requestID];
if (!transaction) {
return;
}
transaction.transactionState = FLEXNetworkTransactionStateFinished;
transaction.duration =
-[transaction.startTime timeIntervalSinceDate:finishedDate];
SKResponseInfo* responseInfo = [[SKResponseInfo alloc]
initWithIndentifier:self.identifierDict[requestID].longLongValue
timestamp:[NSDate timestamp]
response:transaction.response
data:responseBody];
self.identifierDict[requestID] = nil; // Clear the entry
[self.delegate didObserveResponse:responseInfo];
FLEXNetworkTransaction *transaction = self.networkTransactionsForRequestIdentifiers[requestID];
if (!transaction) {
return;
}
transaction.transactionState = FLEXNetworkTransactionStateFinished;
transaction.duration = -[transaction.startTime timeIntervalSinceDate:finishedDate];
SKResponseInfo *responseInfo = [[SKResponseInfo alloc] initWithIndentifier:self.identifierDict[requestID].longLongValue timestamp:[NSDate timestamp] response:transaction.response data:responseBody];
self.identifierDict[requestID] = nil; //Clear the entry
[self.delegate didObserveResponse:responseInfo];
BOOL shouldCache = [responseBody length] > 0;
if (!self.shouldCacheMediaResponses) {
NSArray<NSString*>* ignoredMIMETypePrefixes =
@[ @"audio", @"image", @"video" ];
for (NSString* ignoredPrefix in ignoredMIMETypePrefixes) {
shouldCache = shouldCache &&
![transaction.response.MIMEType hasPrefix:ignoredPrefix];
}
}
BOOL shouldCache = [responseBody length] > 0;
if (!self.shouldCacheMediaResponses) {
NSArray<NSString *> *ignoredMIMETypePrefixes = @[ @"audio", @"image", @"video" ];
for (NSString *ignoredPrefix in ignoredMIMETypePrefixes) {
shouldCache = shouldCache && ![transaction.response.MIMEType hasPrefix:ignoredPrefix];
}
}
if (shouldCache) {
[self.responseCache setObject:responseBody forKey:requestID cost:[responseBody length]];
}
});
if (shouldCache) {
[self.responseCache setObject:responseBody
forKey:requestID
cost:[responseBody length]];
}
});
}
- (void)recordLoadingFailedWithRequestID:(NSString *)requestID error:(NSError *)error
{
dispatch_async(self.queue, ^{
FLEXNetworkTransaction *transaction = self.networkTransactionsForRequestIdentifiers[requestID];
if (!transaction) {
return;
}
- (void)recordLoadingFailedWithRequestID:(NSString*)requestID
error:(NSError*)error {
dispatch_async(self.queue, ^{
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];
self.identifierDict[requestID] = nil; //Clear the entry
[self.delegate didObserveResponse:responseInfo];
transaction.transactionState = FLEXNetworkTransactionStateFailed;
transaction.duration = -[transaction.startTime timeIntervalSinceNow];
transaction.error = error;
});
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;
transaction.duration = -[transaction.startTime timeIntervalSinceNow];
transaction.error = error;
});
}
- (void)recordMechanism:(NSString *)mechanism forRequestID:(NSString *)requestID
{
dispatch_async(self.queue, ^{
FLEXNetworkTransaction *transaction = self.networkTransactionsForRequestIdentifiers[requestID];
if (!transaction) {
return;
}
transaction.requestMechanism = mechanism;
});
- (void)recordMechanism:(NSString*)mechanism forRequestID:(NSString*)requestID {
dispatch_async(self.queue, ^{
FLEXNetworkTransaction* transaction =
self.networkTransactionsForRequestIdentifiers[requestID];
if (!transaction) {
return;
}
transaction.requestMechanism = mechanism;
});
}
@end

View File

@@ -10,35 +10,37 @@
#import "UIKit/UIKit.h"
typedef NS_ENUM(NSInteger, FLEXNetworkTransactionState) {
FLEXNetworkTransactionStateUnstarted,
FLEXNetworkTransactionStateAwaitingResponse,
FLEXNetworkTransactionStateReceivingData,
FLEXNetworkTransactionStateFinished,
FLEXNetworkTransactionStateFailed
FLEXNetworkTransactionStateUnstarted,
FLEXNetworkTransactionStateAwaitingResponse,
FLEXNetworkTransactionStateReceivingData,
FLEXNetworkTransactionStateFinished,
FLEXNetworkTransactionStateFailed
};
@interface FLEXNetworkTransaction : NSObject
@property (nonatomic, copy) NSString *requestID;
@property(nonatomic, copy) NSString* requestID;
@property (nonatomic, strong) NSURLRequest *request;
@property (nonatomic, strong) NSURLResponse *response;
@property (nonatomic, copy) NSString *requestMechanism;
@property (nonatomic, assign) FLEXNetworkTransactionState transactionState;
@property (nonatomic, strong) NSError *error;
@property(nonatomic, strong) NSURLRequest* request;
@property(nonatomic, strong) NSURLResponse* response;
@property(nonatomic, copy) NSString* requestMechanism;
@property(nonatomic, assign) FLEXNetworkTransactionState transactionState;
@property(nonatomic, strong) NSError* error;
@property (nonatomic, strong) NSDate *startTime;
@property (nonatomic, assign) NSTimeInterval latency;
@property (nonatomic, assign) NSTimeInterval duration;
@property(nonatomic, strong) NSDate* startTime;
@property(nonatomic, assign) NSTimeInterval latency;
@property(nonatomic, assign) NSTimeInterval duration;
@property (nonatomic, assign) int64_t receivedDataLength;
@property(nonatomic, assign) int64_t receivedDataLength;
/// Only applicable for image downloads. A small thumbnail to preview the full response.
@property (nonatomic, strong) UIImage *responseThumbnail;
/// 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;
@property(nonatomic, strong, readonly) NSData* cachedRequestBody;
+ (NSString *)readableStringFromTransactionState:(FLEXNetworkTransactionState)state;
+ (NSString*)readableStringFromTransactionState:
(FLEXNetworkTransactionState)state;
@end

View File

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

View File

@@ -12,13 +12,15 @@
#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)
+ (NSNumber *)random;
+ (NSNumber*)random;
@end
@@ -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,86 +7,102 @@
#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
{
if ([cls instancesRespondToSelector:selector]) {
unsigned int numMethods = 0;
Method *methods = class_copyMethodList(cls, &numMethods);
+ (BOOL)instanceRespondsButDoesNotImplementSelector:(SEL)selector
class:(Class)cls {
if ([cls instancesRespondToSelector:selector]) {
unsigned int numMethods = 0;
Method* methods = class_copyMethodList(cls, &numMethods);
BOOL implementsSelector = NO;
for (int index = 0; index < numMethods; index++) {
SEL methodSelector = method_getName(methods[index]);
if (selector == methodSelector) {
implementsSelector = YES;
break;
}
}
free(methods);
if (!implementsSelector) {
return YES;
}
BOOL implementsSelector = NO;
for (int index = 0; index < numMethods; index++) {
SEL methodSelector = method_getName(methods[index]);
if (selector == methodSelector) {
implementsSelector = YES;
break;
}
}
return NO;
free(methods);
if (!implementsSelector) {
return YES;
}
}
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.
Method originalMethod = class_getInstanceMethod(className, originalSelector);
if (!originalMethod) {
return;
}
+ (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));
Method newMethod = class_getInstanceMethod(className, swizzledSelector);
method_exchangeImplementations(originalMethod, newMethod);
IMP implementation = imp_implementationWithBlock(block);
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
{
if ([self instanceRespondsButDoesNotImplementSelector:selector class:cls]) {
return;
}
+ (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);
Method oldMethod = class_getInstanceMethod(cls, selector);
if (oldMethod) {
class_addMethod(
cls, swizzledSelector, implementation, methodDescription.types);
Method newMethod = class_getInstanceMethod(cls, swizzledSelector);
Method newMethod = class_getInstanceMethod(cls, swizzledSelector);
method_exchangeImplementations(oldMethod, newMethod);
} else {
class_addMethod(cls, selector, implementation, methodDescription.types);
}
method_exchangeImplementations(oldMethod, newMethod);
} else {
class_addMethod(cls, selector, implementation, methodDescription.types);
}
}
@end
@implementation NSNumber (SonarUtility)
+ (NSNumber *)random {
+ (NSNumber*)random {
int64_t identifier;
arc4random_buf(&identifier, sizeof(int64_t));
return @(identifier);
@@ -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,12 +7,12 @@
#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;
@property (weak, nonatomic) id<SKNetworkReporterDelegate> delegate;
@property(weak, nonatomic) id<SKNetworkReporterDelegate> delegate;
@end

View File

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

View File

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

View File

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

View File

@@ -10,15 +10,15 @@
#import <FlipperKit/FlipperResponder.h>
#import "FKUserDefaultsSwizzleUtility.h"
static NSString *const kStandardUserDefaultsName = @"Standard UserDefaults";
static NSString *const kAppSuiteUserDefaultsName = @"App Suite UserDefaults";
static NSString* const kStandardUserDefaultsName = @"Standard UserDefaults";
static NSString* const kAppSuiteUserDefaultsName = @"App Suite UserDefaults";
@interface FKUserDefaultsPlugin ()
@property (nonatomic, strong) id<FlipperConnection> flipperConnection;
@property (nonatomic, strong) NSUserDefaults *standardUserDefaults;
@property (nonatomic, strong) NSUserDefaults *appSuiteUserDefaults;
@property (nonatomic, copy) NSString *key;
@property (nonatomic, copy) NSString *suiteName;
@property(nonatomic, strong) id<FlipperConnection> flipperConnection;
@property(nonatomic, strong) NSUserDefaults* standardUserDefaults;
@property(nonatomic, strong) NSUserDefaults* appSuiteUserDefaults;
@property(nonatomic, copy) NSString* key;
@property(nonatomic, copy) NSString* suiteName;
@end
@implementation FKUserDefaultsPlugin
@@ -27,89 +27,106 @@ 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) {
__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)
changedWithValue:firstArg
key:secondArg];
}];
[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)
changedWithValue:firstArg
key:secondArg];
}];
}
return self;
}
- (instancetype)initWithSuiteName:(NSString *)suiteName {
if (self = [self init]) {
_suiteName = suiteName;
if (_suiteName) {
_appSuiteUserDefaults = [[NSUserDefaults alloc] initWithSuiteName:_suiteName];
}
- (instancetype)initWithSuiteName:(NSString*)suiteName {
if (self = [self init]) {
_suiteName = suiteName;
if (_suiteName) {
_appSuiteUserDefaults =
[[NSUserDefaults alloc] initWithSuiteName:_suiteName];
}
return self;
}
return self;
}
- (void)didConnect:(id<FlipperConnection>)connection {
self.flipperConnection = connection;
[connection receive:@"getAllSharedPreferences" withBlock:^(NSDictionary *params, id<FlipperResponder> responder) {
NSMutableDictionary *userDefaults = [NSMutableDictionary new];
userDefaults[kStandardUserDefaultsName] = [self.standardUserDefaults dictionaryRepresentation];
if (self.appSuiteUserDefaults) {
userDefaults[kAppSuiteUserDefaultsName] = [self.appSuiteUserDefaults dictionaryRepresentation];
}
[responder success:userDefaults];
}];
[connection receive:@"setSharedPreference" withBlock:^(NSDictionary *params , id<FlipperResponder> responder) {
NSUserDefaults *sharedPreferences = [self sharedPreferencesForParams:params];
NSString *preferenceName = params[@"preferenceName"];
[sharedPreferences setObject:params[@"preferenceValue"] forKey:preferenceName];
[responder success:[sharedPreferences dictionaryRepresentation]];
}];
self.flipperConnection = connection;
[connection receive:@"getAllSharedPreferences"
withBlock:^(NSDictionary* params, id<FlipperResponder> responder) {
NSMutableDictionary* userDefaults = [NSMutableDictionary new];
userDefaults[kStandardUserDefaultsName] =
[self.standardUserDefaults dictionaryRepresentation];
if (self.appSuiteUserDefaults) {
userDefaults[kAppSuiteUserDefaultsName] =
[self.appSuiteUserDefaults dictionaryRepresentation];
}
[responder success:userDefaults];
}];
[connection receive:@"setSharedPreference"
withBlock:^(NSDictionary* params, id<FlipperResponder> responder) {
NSUserDefaults* sharedPreferences =
[self sharedPreferencesForParams:params];
NSString* preferenceName = params[@"preferenceName"];
[sharedPreferences setObject:params[@"preferenceValue"]
forKey:preferenceName];
[responder success:[sharedPreferences dictionaryRepresentation]];
}];
}
- (void)didDisconnect {
self.flipperConnection = nil;
self.flipperConnection = nil;
}
- (NSString *)identifier {
return @"Preferences";
- (NSString*)identifier {
return @"Preferences";
}
#pragma mark - Private methods
- (NSUserDefaults *)sharedPreferencesForParams:(NSDictionary *)params {
NSString *const sharedPreferencesNameKey = @"sharedPreferencesName";
- (NSUserDefaults*)sharedPreferencesForParams:(NSDictionary*)params {
NSString* const sharedPreferencesNameKey = @"sharedPreferencesName";
if (![params[sharedPreferencesNameKey] isKindOfClass:[NSString class]]) {
return _standardUserDefaults;
}
NSString *sharedPreferencesName = params[sharedPreferencesNameKey];
return ([sharedPreferencesName isEqualToString:kAppSuiteUserDefaultsName]
NSString* sharedPreferencesName = params[sharedPreferencesNameKey];
return (
[sharedPreferencesName isEqualToString:kAppSuiteUserDefaultsName]
? _appSuiteUserDefaults
: _standardUserDefaults);
}
- (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];
if (!value) {
[params setObject:@"YES" forKey:@"deleted"];
} else {
[params setObject:value forKey:@"value"];
}
NSString *sharedPreferencesName = (userDefaults == _standardUserDefaults
? kStandardUserDefaultsName
: kAppSuiteUserDefaultsName);
[params setObject:sharedPreferencesName forKey:@"preferences"];
[self.flipperConnection send:@"sharedPreferencesChange" withParams:[params copy]];
- (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];
if (!value) {
[params setObject:@"YES" forKey:@"deleted"];
} else {
[params setObject:value forKey:@"value"];
}
NSString* sharedPreferencesName =
(userDefaults == _standardUserDefaults ? kStandardUserDefaultsName
: kAppSuiteUserDefaultsName);
[params setObject:sharedPreferencesName forKey:@"preferences"];
[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

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