Refactor Layout Plugin
Summary: This diff moves the iOS descriptors and other layout helpers into its own buck target. Earlier everything was part of the FlipperKitLayoutPlugin target. When kcui, tried to add macos descriptors, we realised that FlipperKitLayoutPlugin doesn't have macos platform in it and thus he had to put #if TARGET_OS_SIMULATOR check in iOS descriptors and at some other places. In order to make the integration easier I decided to split the Layout Plugin in following way. ``` FlipperKitLayoutPlugin -> FlipperKitLayoutIOSDescriptors (platform set as IOS) -> FlipperKitLayoutHelpers (used in iOS Descriptors and usefule for Macos too) -> FlipperKitLayoutMacOSDescriptors(coming soon by kcui)(platform set as MacOS) ``` Reviewed By: kcui Differential Revision: D27127587 fbshipit-source-id: f108ef81914297e93c886fe53dabf0a4bf11ebc1
This commit is contained in:
committed by
Facebook GitHub Bot
parent
8c85da5bc8
commit
790f23301e
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class SKNodeDescriptor;
|
||||
|
||||
@protocol SKDescriptorMapperProtocol<NSObject>
|
||||
|
||||
- (instancetype)initWithDefaults;
|
||||
|
||||
- (SKNodeDescriptor*)descriptorForClass:(Class)cls;
|
||||
|
||||
- (void)registerDescriptor:(SKNodeDescriptor*)descriptor forClass:(Class)cls;
|
||||
|
||||
- (NSArray<SKNodeDescriptor*>*)allDescriptors;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@protocol SKInvalidationDelegate
|
||||
|
||||
- (void)invalidateNode:(id<NSObject>)node;
|
||||
- (void)updateNodeReference:(id<NSObject>)node;
|
||||
|
||||
@end
|
||||
|
||||
@interface SKInvalidation : NSObject
|
||||
|
||||
+ (instancetype)sharedInstance;
|
||||
|
||||
+ (void)enableInvalidations;
|
||||
|
||||
@property(nonatomic, weak) id<SKInvalidationDelegate> delegate;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#if FB_SONARKIT_ENABLED
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "SKInvalidation.h"
|
||||
#import "UICollectionView+SKInvalidation.h"
|
||||
#import "UIView+SKInvalidation.h"
|
||||
|
||||
@implementation SKInvalidation
|
||||
|
||||
+ (instancetype)sharedInstance {
|
||||
static SKInvalidation* sInstance = nil;
|
||||
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
sInstance = [SKInvalidation new];
|
||||
});
|
||||
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
+ (void)enableInvalidations {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
[UIView enableInvalidation];
|
||||
[UICollectionView enableInvalidations];
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:self
|
||||
selector:@selector(windowDidBecomeVisible:)
|
||||
name:UIWindowDidBecomeVisibleNotification
|
||||
object:nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:self
|
||||
selector:@selector(windowDidBecomeHidden:)
|
||||
name:UIWindowDidBecomeHiddenNotification
|
||||
object:nil];
|
||||
});
|
||||
}
|
||||
|
||||
+ (void)windowDidBecomeVisible:(NSNotification*)notification {
|
||||
[[SKInvalidation sharedInstance].delegate
|
||||
invalidateNode:[notification.object nextResponder]];
|
||||
}
|
||||
|
||||
+ (void)windowDidBecomeHidden:(NSNotification*)notification {
|
||||
[[SKInvalidation sharedInstance].delegate
|
||||
invalidateNode:[notification.object nextResponder]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface SKNamed<__covariant T> : NSObject
|
||||
|
||||
+ (instancetype)newWithName:(NSString*)name withValue:(T)value;
|
||||
|
||||
@property(nonatomic, readonly) NSString* name;
|
||||
@property(nonatomic, readonly) T value;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#if FB_SONARKIT_ENABLED
|
||||
|
||||
#import "SKNamed.h"
|
||||
|
||||
@implementation SKNamed
|
||||
|
||||
+ (instancetype)newWithName:(NSString*)name withValue:(id)value {
|
||||
return [[SKNamed alloc] initWithName:name withValue:value];
|
||||
}
|
||||
|
||||
- (instancetype)initWithName:(NSString*)name withValue:(id)value {
|
||||
if (self = [super init]) {
|
||||
_name = name;
|
||||
_value = value;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString*)description {
|
||||
return [NSString stringWithFormat:@"%@: %@", _name, _value];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import <FlipperKitLayoutHelpers/FlipperKitLayoutDescriptorMapperProtocol.h>
|
||||
#import "SKNamed.h"
|
||||
#import "SKTouch.h"
|
||||
|
||||
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.
|
||||
*/
|
||||
@interface SKNodeDescriptor<__covariant T> : NSObject
|
||||
|
||||
/**
|
||||
If the descriptor class is dependent on some set-up, use this.
|
||||
This is invoked once Sonar connects.
|
||||
*/
|
||||
- (void)setUp;
|
||||
|
||||
/**
|
||||
Initializes the node-descriptor with a SKDescriptorMapper which contains
|
||||
mappings between Class -> SKNodeDescriptor<Class>.
|
||||
*/
|
||||
- (instancetype)initWithDescriptorMapper:(id<SKDescriptorMapperProtocol>)mapper;
|
||||
|
||||
/**
|
||||
Gets the node-descriptor registered for a specific class.
|
||||
*/
|
||||
- (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.
|
||||
*/
|
||||
- (NSString*)identifierForNode:(T)node;
|
||||
|
||||
/**
|
||||
When the setData command is received from Flipper to change a node's data,
|
||||
an "invalidateWithData" command is sent back to signal that the node has
|
||||
changed. However sometimes you may want to invalidate some other node,
|
||||
not the node that had its data actually modified; usually some ancestor.
|
||||
This method allows you to substitute another node's identifier.
|
||||
If you do not override it, the default behavior is to simply return
|
||||
the node's identifier.
|
||||
*/
|
||||
- (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.
|
||||
*/
|
||||
- (NSString*)nameForNode:(T)node;
|
||||
|
||||
/**
|
||||
The number of children this node exposes in the layout hierarchy.
|
||||
*/
|
||||
- (NSUInteger)childCountForNode:(T)node;
|
||||
|
||||
/**
|
||||
Get the child for a specific node at a specified index.
|
||||
*/
|
||||
- (id)childForNode:(T)node atIndex:(NSUInteger)index;
|
||||
|
||||
/**
|
||||
Get the data to show for this node in the sidebar of the Sonar application. The
|
||||
objects will be shown in order by SKNamed.name as their header.
|
||||
*/
|
||||
- (NSArray<SKNamed<NSDictionary*>*>*)dataForNode:(T)node;
|
||||
|
||||
/**
|
||||
Get the extra info to pass it back to Sonar application without showing them in
|
||||
the sidebar.
|
||||
*/
|
||||
- (NSArray<SKNamed<NSDictionary*>*>*)extraInfoForNode:(T)node;
|
||||
|
||||
/**
|
||||
Get the attributes for this node. Attributes will be showed in the Sonar
|
||||
application right next to the name of the node.
|
||||
*/
|
||||
- (NSArray<SKNamed<NSString*>*>*)attributesForNode:(T)node;
|
||||
|
||||
/**
|
||||
A mapping of the path for a specific value, and a block responsible for
|
||||
updating its corresponding value for a specific node.
|
||||
|
||||
The paths (string) is dependent on what `dataForNode` returns (e.g
|
||||
"SKNodeDescriptor.name").
|
||||
*/
|
||||
- (NSDictionary<NSString*, SKNodeUpdateData>*)dataMutationsForNode:(T)node;
|
||||
|
||||
/**
|
||||
This is used in order to highlight any specific node which is currently
|
||||
selected in the Sonar application. The plugin automatically takes care of
|
||||
de-selecting the previously highlighted node.
|
||||
*/
|
||||
- (void)setHighlighted:(BOOL)highlighted forNode:(T)node;
|
||||
|
||||
/**
|
||||
Perform hit testing on the given node. Either continue the search in
|
||||
one of the children of the node, or finish the hit testing on this
|
||||
node.
|
||||
*/
|
||||
- (void)hitTest:(SKTouch*)point forNode:(T)node;
|
||||
|
||||
/**
|
||||
Invalidate a specific node. This is called once a node is removed or added
|
||||
from or to the layout hierarchy.
|
||||
*/
|
||||
- (void)invalidateNode:(T)node;
|
||||
|
||||
/**
|
||||
The decoration for this node. Valid values are defined in the Sonar
|
||||
applictation.
|
||||
*/
|
||||
- (NSString*)decorationForNode:(T)node;
|
||||
|
||||
/**
|
||||
Whether the node matches the given query.
|
||||
Used for layout search.
|
||||
*/
|
||||
- (BOOL)matchesQuery:(NSString*)query forNode:(T)node;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#if FB_SONARKIT_ENABLED
|
||||
|
||||
#import "SKNodeDescriptor.h"
|
||||
#import <FlipperKitLayoutTextSearchable/FKTextSearchable.h>
|
||||
|
||||
@implementation SKNodeDescriptor {
|
||||
id<SKDescriptorMapperProtocol> _mapper;
|
||||
}
|
||||
|
||||
- (void)setUp {
|
||||
}
|
||||
|
||||
- (instancetype)initWithDescriptorMapper:
|
||||
(id<SKDescriptorMapperProtocol>)mapper {
|
||||
if (self = [super init]) {
|
||||
_mapper = mapper;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (SKNodeDescriptor*)descriptorForClass:(Class)cls {
|
||||
return [_mapper descriptorForClass:cls];
|
||||
}
|
||||
|
||||
- (NSString*)identifierForNode:(id)node {
|
||||
@throw [NSString
|
||||
stringWithFormat:@"need to implement %@", NSStringFromSelector(_cmd)];
|
||||
}
|
||||
|
||||
- (NSString*)identifierForInvalidation:(id)node {
|
||||
return [self identifierForNode:node];
|
||||
}
|
||||
|
||||
- (NSString*)nameForNode:(id)node {
|
||||
return NSStringFromClass([node class]);
|
||||
}
|
||||
|
||||
- (NSUInteger)childCountForNode:(id)node {
|
||||
@throw [NSString
|
||||
stringWithFormat:@"need to implement %@", NSStringFromSelector(_cmd)];
|
||||
}
|
||||
|
||||
- (id)childForNode:(id)node atIndex:(NSUInteger)index {
|
||||
@throw [NSString
|
||||
stringWithFormat:@"need to implement %@", NSStringFromSelector(_cmd)];
|
||||
}
|
||||
|
||||
- (NSDictionary<NSString*, SKNodeUpdateData>*)dataMutationsForNode:(id)node {
|
||||
return @{};
|
||||
}
|
||||
|
||||
- (NSArray<SKNamed<NSDictionary*>*>*)dataForNode:(id)node {
|
||||
return @[];
|
||||
}
|
||||
|
||||
- (NSArray<SKNamed<NSDictionary*>*>*)extraInfoForNode:(id)node {
|
||||
return @[];
|
||||
}
|
||||
|
||||
- (NSArray<SKNamed<NSString*>*>*)attributesForNode:(id)node {
|
||||
return @[];
|
||||
}
|
||||
|
||||
- (void)setHighlighted:(BOOL)highlighted forNode:(id)node {
|
||||
}
|
||||
|
||||
- (void)hitTest:(SKTouch*)point forNode:(id)node {
|
||||
}
|
||||
|
||||
- (void)invalidateNode:(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)string:(NSString*)string contains:(NSString*)substring {
|
||||
return string != nil && substring != nil &&
|
||||
[string rangeOfString:substring options:NSCaseInsensitiveSearch]
|
||||
.location != NSNotFound;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@protocol SKSonarValueCoder
|
||||
|
||||
+ (instancetype)fromSonarValue:(id)sonarValue;
|
||||
|
||||
- (NSDictionary<NSString*, id<NSObject>>*)sonarValue;
|
||||
|
||||
@end
|
||||
|
||||
class SKObject {
|
||||
public:
|
||||
SKObject(CGRect rect);
|
||||
SKObject(CGSize size);
|
||||
SKObject(CGPoint point);
|
||||
SKObject(UIEdgeInsets insets);
|
||||
SKObject(CGAffineTransform transform);
|
||||
SKObject(id<SKSonarValueCoder> value);
|
||||
SKObject(id value);
|
||||
|
||||
operator id<NSObject>() const noexcept {
|
||||
return _actual ?: [NSNull null];
|
||||
}
|
||||
|
||||
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){};
|
||||
|
||||
operator id<NSObject>() {
|
||||
convertToMutable();
|
||||
return _actual;
|
||||
}
|
||||
|
||||
protected:
|
||||
BOOL _convertedToMutable = NO;
|
||||
void convertToMutable();
|
||||
};
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#if FB_SONARKIT_ENABLED
|
||||
|
||||
#import "SKObject.h"
|
||||
|
||||
SKObject::SKObject(CGRect rect) {
|
||||
_actual = @{@"origin" : SKObject(rect.origin), @"size" : SKObject(rect.size)};
|
||||
}
|
||||
|
||||
SKObject::SKObject(CGSize size) {
|
||||
_actual = @{@"height" : @(size.height), @"width" : @(size.width)};
|
||||
}
|
||||
|
||||
SKObject::SKObject(CGPoint point) {
|
||||
_actual = @{@"x" : @(point.x), @"y" : @(point.y)};
|
||||
}
|
||||
|
||||
SKObject::SKObject(UIEdgeInsets insets) {
|
||||
_actual = @{
|
||||
@"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),
|
||||
};
|
||||
}
|
||||
|
||||
SKObject::SKObject(id<SKSonarValueCoder> value) : _actual([value sonarValue]) {}
|
||||
|
||||
SKObject::SKObject(id value) : _actual(value) {}
|
||||
|
||||
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"];
|
||||
}
|
||||
|
||||
return 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]),
|
||||
};
|
||||
}
|
||||
|
||||
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;
|
||||
mutableObject[key] = _SKMutable(objectValue);
|
||||
} else {
|
||||
mutableObject[key] = _SKValue(value, YES);
|
||||
}
|
||||
}
|
||||
|
||||
return mutableObject;
|
||||
}
|
||||
|
||||
void SKMutableObject::convertToMutable() {
|
||||
if (_convertedToMutable) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_objectType(_actual) == nil &&
|
||||
[_actual isKindOfClass:[NSDictionary class]]) {
|
||||
auto object = (const NSDictionary<NSString*, id<NSObject>>*)_actual;
|
||||
_actual = _SKMutable(object);
|
||||
} else {
|
||||
_actual = _SKValue(_actual, YES);
|
||||
}
|
||||
|
||||
_convertedToMutable = YES;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#ifndef SKSearchResultNode_h
|
||||
#define SKSearchResultNode_h
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface SKSearchResultNode : NSObject
|
||||
|
||||
@property(nonatomic, copy, readonly) NSString* nodeId;
|
||||
|
||||
- (instancetype)initWithNode:(NSString*)nodeId
|
||||
asMatch:(BOOL)isMatch
|
||||
withElement:(NSDictionary*)element
|
||||
andChildren:(NSArray<SKSearchResultNode*>*)children;
|
||||
|
||||
- (NSDictionary*)toNSDictionary;
|
||||
|
||||
@end
|
||||
#endif /* SKSearchResultNode_h */
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "SKSearchResultNode.h"
|
||||
|
||||
@implementation SKSearchResultNode {
|
||||
NSString* _nodeId;
|
||||
BOOL _isMatch;
|
||||
NSDictionary* _element;
|
||||
NSArray<SKSearchResultNode*>* _children;
|
||||
}
|
||||
|
||||
- (instancetype)initWithNode:(NSString*)nodeId
|
||||
asMatch:(BOOL)isMatch
|
||||
withElement:(NSDictionary*)element
|
||||
andChildren:(NSArray<SKSearchResultNode*>*)children {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_nodeId = nodeId;
|
||||
_isMatch = isMatch;
|
||||
_element = element;
|
||||
_children = children;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSDictionary*)toNSDictionary {
|
||||
if (_element == nil) {
|
||||
return nil;
|
||||
}
|
||||
NSMutableArray<NSDictionary*>* childArray;
|
||||
if (_children) {
|
||||
childArray = [NSMutableArray new];
|
||||
for (SKSearchResultNode* child in _children) {
|
||||
NSDictionary* childDict = [child toNSDictionary];
|
||||
if (childDict) {
|
||||
[childArray addObject:childDict];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
childArray = nil;
|
||||
}
|
||||
return @{
|
||||
@"id" : _nodeId,
|
||||
@"isMatch" : @(_isMatch),
|
||||
@"element" : _element,
|
||||
@"children" : childArray ?: [NSNull null]
|
||||
};
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
typedef void (^SKTapReceiver)(CGPoint touchPoint);
|
||||
|
||||
@protocol SKTapListener
|
||||
|
||||
@property(nonatomic, readonly) BOOL isMounted;
|
||||
|
||||
- (void)mountWithFrame:(CGRect)frame;
|
||||
|
||||
- (void)unmount;
|
||||
|
||||
- (void)listenForTapWithBlock:(SKTapReceiver)receiver;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "SKTapListener.h"
|
||||
|
||||
@interface SKTapListenerImpl
|
||||
: NSObject<SKTapListener, UIGestureRecognizerDelegate>
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#if FB_SONARKIT_ENABLED
|
||||
|
||||
#import "SKTapListenerImpl.h"
|
||||
|
||||
#import "SKHiddenWindow.h"
|
||||
|
||||
#import <FlipperKitHighlightOverlay/SKHighlightOverlay.h>
|
||||
|
||||
@implementation SKTapListenerImpl {
|
||||
NSMutableArray<SKTapReceiver>* _receiversWaitingForInput;
|
||||
UITapGestureRecognizer* _gestureRecognizer;
|
||||
|
||||
SKHiddenWindow* _overlayWindow;
|
||||
}
|
||||
|
||||
@synthesize isMounted = _isMounted;
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_receiversWaitingForInput = [NSMutableArray new];
|
||||
|
||||
_gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
|
||||
action:nil];
|
||||
_gestureRecognizer.delegate = self;
|
||||
|
||||
_isMounted = NO;
|
||||
|
||||
_overlayWindow = [SKHiddenWindow new];
|
||||
_overlayWindow.hidden = YES;
|
||||
_overlayWindow.windowLevel = UIWindowLevelAlert;
|
||||
_overlayWindow.backgroundColor = [SKHighlightOverlay overlayColor];
|
||||
|
||||
[_overlayWindow addGestureRecognizer:_gestureRecognizer];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)mountWithFrame:(CGRect)frame {
|
||||
if (_isMounted) {
|
||||
return;
|
||||
}
|
||||
|
||||
[_overlayWindow setFrame:frame];
|
||||
[_overlayWindow makeKeyAndVisible];
|
||||
_overlayWindow.hidden = NO;
|
||||
[[UIApplication sharedApplication].delegate.window addSubview:_overlayWindow];
|
||||
_isMounted = YES;
|
||||
}
|
||||
|
||||
- (void)unmount {
|
||||
if (!_isMounted) {
|
||||
return;
|
||||
}
|
||||
|
||||
[_receiversWaitingForInput removeAllObjects];
|
||||
[_overlayWindow removeFromSuperview];
|
||||
_overlayWindow.hidden = YES;
|
||||
_isMounted = NO;
|
||||
}
|
||||
|
||||
- (void)listenForTapWithBlock:(SKTapReceiver)receiver {
|
||||
[_receiversWaitingForInput addObject:receiver];
|
||||
}
|
||||
|
||||
- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
|
||||
shouldReceiveTouch:(UITouch*)touch {
|
||||
if ([_receiversWaitingForInput count] == 0) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
CGPoint touchPoint = [touch locationInView:_overlayWindow];
|
||||
|
||||
for (SKTapReceiver recv in _receiversWaitingForInput) {
|
||||
recv(touchPoint);
|
||||
}
|
||||
|
||||
[_receiversWaitingForInput removeAllObjects];
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <FlipperKitLayoutHelpers/FlipperKitLayoutDescriptorMapperProtocol.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
typedef void (^SKTouchFinishDelegate)(id<NSObject> currentNode);
|
||||
typedef void (^SKProcessFinishDelegate)(NSDictionary* tree);
|
||||
|
||||
@interface SKTouch : NSObject
|
||||
|
||||
- (instancetype)initWithTouchPoint:(CGPoint)touchPoint
|
||||
withRootNode:(id<NSObject>)node
|
||||
withDescriptorMapper:(id<SKDescriptorMapperProtocol>)mapper
|
||||
finishWithBlock:(SKTouchFinishDelegate)d;
|
||||
|
||||
- (void)continueWithChildIndex:(NSUInteger)childIndex
|
||||
withOffset:(CGPoint)offset;
|
||||
|
||||
- (void)finish;
|
||||
|
||||
- (void)retrieveSelectTree:(SKProcessFinishDelegate)callback;
|
||||
|
||||
- (BOOL)containedIn:(CGRect)bounds;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#if FB_SONARKIT_ENABLED
|
||||
|
||||
#import "SKTouch.h"
|
||||
#import "SKNodeDescriptor.h"
|
||||
|
||||
@implementation SKTouch {
|
||||
SKTouchFinishDelegate _onFinish;
|
||||
|
||||
CGPoint _currentTouchPoint;
|
||||
|
||||
id<SKDescriptorMapperProtocol> _descriptorMapper;
|
||||
|
||||
NSMutableArray<id<NSObject>>* _nodeStack;
|
||||
NSMutableArray<NSMutableDictionary*>* _treeStack;
|
||||
}
|
||||
|
||||
- (instancetype)initWithTouchPoint:(CGPoint)touchPoint
|
||||
withRootNode:(id<NSObject>)node
|
||||
withDescriptorMapper:(id<SKDescriptorMapperProtocol>)mapper
|
||||
finishWithBlock:(SKTouchFinishDelegate)finishBlock {
|
||||
if (self = [super init]) {
|
||||
_onFinish = finishBlock;
|
||||
_currentTouchPoint = touchPoint;
|
||||
_descriptorMapper = mapper;
|
||||
_nodeStack = [NSMutableArray new];
|
||||
[_nodeStack addObject:node];
|
||||
_treeStack = [NSMutableArray new];
|
||||
[_treeStack addObject:[[NSMutableDictionary alloc] init]];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)continueWithChildIndex:(NSUInteger)childIndex
|
||||
withOffset:(CGPoint)offset {
|
||||
_currentTouchPoint.x -= offset.x;
|
||||
_currentTouchPoint.y -= offset.y;
|
||||
|
||||
id<NSObject> currentNode = _nodeStack.lastObject;
|
||||
SKNodeDescriptor* descriptor =
|
||||
[_descriptorMapper descriptorForClass:[currentNode class]];
|
||||
id<NSObject> nextNode = [descriptor childForNode:currentNode
|
||||
atIndex:childIndex];
|
||||
[_nodeStack addObject:nextNode];
|
||||
[_treeStack addObject:[[NSMutableDictionary alloc] init]];
|
||||
|
||||
descriptor = [_descriptorMapper descriptorForClass:[nextNode class]];
|
||||
NSString* currentId = [descriptor identifierForNode:nextNode];
|
||||
[descriptor hitTest:self forNode:nextNode];
|
||||
|
||||
// After finish this component
|
||||
_currentTouchPoint.x += offset.x;
|
||||
_currentTouchPoint.y += offset.y;
|
||||
[_nodeStack removeLastObject];
|
||||
NSDictionary* currentDict = _treeStack.lastObject;
|
||||
[_treeStack removeLastObject];
|
||||
[_treeStack.lastObject setObject:currentDict forKey:currentId];
|
||||
}
|
||||
|
||||
- (void)finish {
|
||||
_onFinish(_nodeStack.lastObject);
|
||||
}
|
||||
|
||||
- (void)retrieveSelectTree:(SKProcessFinishDelegate)callback {
|
||||
callback(_treeStack.lastObject);
|
||||
[_treeStack removeAllObjects];
|
||||
}
|
||||
|
||||
- (BOOL)containedIn:(CGRect)bounds {
|
||||
return CGRectContainsPoint(bounds, _currentTouchPoint);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import <FlipperKit/SKMacros.h>
|
||||
|
||||
FB_LINK_REQUIRE_CATEGORY(UICollectionView_SKInvalidation)
|
||||
@interface UICollectionView (SKInvalidation)
|
||||
|
||||
+ (void)enableInvalidations;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#if FB_SONARKIT_ENABLED
|
||||
|
||||
#import "UICollectionView+SKInvalidation.h"
|
||||
|
||||
#import "SKInvalidation.h"
|
||||
#import "SKSwizzle.h"
|
||||
|
||||
FB_LINKABLE(UICollectionView_SKInvalidation)
|
||||
@implementation UICollectionView (SKInvalidation)
|
||||
|
||||
+ (void)enableInvalidations {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
swizzleMethods(
|
||||
[self class],
|
||||
@selector(cellForItemAtIndexPath:),
|
||||
@selector(swizzle_cellForItemAtIndexPath:));
|
||||
});
|
||||
}
|
||||
|
||||
- (UICollectionViewCell*)swizzle_cellForItemAtIndexPath:
|
||||
(NSIndexPath*)indexPath {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[[SKInvalidation sharedInstance].delegate invalidateNode:self];
|
||||
});
|
||||
|
||||
return [self swizzle_cellForItemAtIndexPath:indexPath];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import <FlipperKit/SKMacros.h>
|
||||
|
||||
#import "SKObject.h"
|
||||
|
||||
FB_LINK_REQUIRE_CATEGORY(UIColor_SonarValueCoder)
|
||||
@interface UIColor (SonarValueCoder)<SKSonarValueCoder>
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#if FB_SONARKIT_ENABLED
|
||||
|
||||
#import "UIColor+SKSonarValueCoder.h"
|
||||
|
||||
FB_LINKABLE(UIColor_SonarValueCoder)
|
||||
@implementation UIColor (SonarValueCoder)
|
||||
|
||||
+ (instancetype)fromSonarValue:(NSNumber*)sonarValue {
|
||||
NSUInteger intColor = [sonarValue integerValue];
|
||||
|
||||
CGFloat r, g, b, a;
|
||||
|
||||
b = CGFloat(intColor & 0xFF) / 255;
|
||||
g = CGFloat((intColor >> 8) & 0xFF) / 255;
|
||||
r = CGFloat((intColor >> 16) & 0xFF) / 255;
|
||||
a = CGFloat((intColor >> 24) & 0xFF) / 255;
|
||||
|
||||
return [[UIColor alloc] initWithRed:r green:g blue:b alpha:a];
|
||||
}
|
||||
|
||||
- (NSDictionary<NSString*, id<NSObject>>*)sonarValue {
|
||||
CGColorSpaceRef colorSpace = CGColorGetColorSpace([self CGColor]);
|
||||
CGColorSpaceModel colorSpaceModel = CGColorSpaceGetModel(colorSpace);
|
||||
|
||||
NSUInteger red, green, blue, alpha;
|
||||
|
||||
switch (colorSpaceModel) {
|
||||
case kCGColorSpaceModelUnknown:
|
||||
case kCGColorSpaceModelRGB: {
|
||||
CGFloat r, g, b, a;
|
||||
[self getRed:&r green:&g blue:&b alpha:&a];
|
||||
|
||||
red = (NSUInteger)(r * 255) & 0xFF;
|
||||
green = (NSUInteger)(g * 255) & 0xFF;
|
||||
blue = (NSUInteger)(b * 255) & 0xFF;
|
||||
alpha = (NSUInteger)(a * 255) & 0xFF;
|
||||
} break;
|
||||
|
||||
case kCGColorSpaceModelMonochrome: {
|
||||
CGFloat a, w;
|
||||
[self getWhite:&w alpha:&a];
|
||||
|
||||
red = green = blue = (NSUInteger)(w * 255) & 0xFF;
|
||||
alpha = (NSUInteger)(a * 255) & 0xFF;
|
||||
} break;
|
||||
|
||||
default:
|
||||
red = green = blue = alpha = 0;
|
||||
}
|
||||
|
||||
NSUInteger intColor = (alpha << 24) | (red << 16) | (green << 8) | blue;
|
||||
return
|
||||
@{@"__type__" : @"color", @"__mutable__" : @NO, @"value" : @(intColor)};
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <FlipperKit/SKMacros.h>
|
||||
|
||||
FB_LINK_REQUIRE_CATEGORY(UIView_SKInvalidation)
|
||||
@interface UIView (SKInvalidation)
|
||||
|
||||
+ (void)enableInvalidation;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#if FB_SONARKIT_ENABLED
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <objc/runtime.h>
|
||||
#import "SKInvalidation.h"
|
||||
#import "SKSwizzle.h"
|
||||
#import "UIView+SKInvalidation.h"
|
||||
|
||||
FB_LINKABLE(UIView_SKInvalidation)
|
||||
@implementation 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(bringSubviewToFront:),
|
||||
@selector(swizzle_bringSubviewToFront:));
|
||||
swizzleMethods(
|
||||
[self class],
|
||||
@selector(sendSubviewToBack:),
|
||||
@selector(swizzle_sendSubviewToBack:));
|
||||
swizzleMethods(
|
||||
[self class],
|
||||
@selector(insertSubview:atIndex:),
|
||||
@selector(swizzle_insertSubview:atIndex:));
|
||||
swizzleMethods(
|
||||
[self class],
|
||||
@selector(insertSubview:aboveSubview:),
|
||||
@selector(swizzle_insertSubview:aboveSubview:));
|
||||
swizzleMethods(
|
||||
[self class],
|
||||
@selector(insertSubview:belowSubview:),
|
||||
@selector(swizzle_insertSubview:belowSubview:));
|
||||
swizzleMethods(
|
||||
[self class],
|
||||
@selector(exchangeSubviewAtIndex:withSubviewAtIndex:),
|
||||
@selector(swizzle_exchangeSubviewAtIndex:withSubviewAtIndex:));
|
||||
swizzleMethods(
|
||||
[self class],
|
||||
@selector(removeFromSuperview),
|
||||
@selector(swizzle_removeFromSuperview));
|
||||
});
|
||||
}
|
||||
|
||||
- (void)swizzle_setHidden:(BOOL)hidden {
|
||||
[self swizzle_setHidden:hidden];
|
||||
|
||||
id<SKInvalidationDelegate> delegate =
|
||||
[SKInvalidation sharedInstance].delegate;
|
||||
if (delegate != nil) {
|
||||
[delegate invalidateNode:self.superview];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)swizzle_addSubview:(UIView*)view {
|
||||
[self swizzle_addSubview:view];
|
||||
[[SKInvalidation sharedInstance].delegate invalidateNode:self];
|
||||
}
|
||||
|
||||
- (void)swizzle_bringSubviewToFront:(UIView*)subview {
|
||||
[self swizzle_bringSubviewToFront:subview];
|
||||
[[SKInvalidation sharedInstance].delegate invalidateNode:self];
|
||||
}
|
||||
|
||||
- (void)swizzle_sendSubviewToBack:(UIView*)subview {
|
||||
[self swizzle_sendSubviewToBack:subview];
|
||||
[[SKInvalidation sharedInstance].delegate invalidateNode:self];
|
||||
}
|
||||
|
||||
- (void)swizzle_insertSubview:(UIView*)subview atIndex:(NSInteger)index {
|
||||
[self swizzle_insertSubview:subview atIndex:index];
|
||||
[[SKInvalidation sharedInstance].delegate invalidateNode:self];
|
||||
}
|
||||
|
||||
- (void)swizzle_insertSubview:(UIView*)subview
|
||||
aboveSubview:(UIView*)siblingSubview {
|
||||
[self swizzle_insertSubview:subview aboveSubview:siblingSubview];
|
||||
[[SKInvalidation sharedInstance].delegate invalidateNode:self];
|
||||
}
|
||||
|
||||
- (void)swizzle_insertSubview:(UIView*)subview
|
||||
belowSubview:(UIView*)siblingSubview {
|
||||
[self swizzle_insertSubview:subview belowSubview:siblingSubview];
|
||||
[[SKInvalidation sharedInstance].delegate invalidateNode:self];
|
||||
}
|
||||
|
||||
- (void)swizzle_exchangeSubviewAtIndex:(NSInteger)index1
|
||||
withSubviewAtIndex:(NSInteger)index2 {
|
||||
[self swizzle_exchangeSubviewAtIndex:index1 withSubviewAtIndex:index2];
|
||||
[[SKInvalidation sharedInstance].delegate invalidateNode:self];
|
||||
}
|
||||
|
||||
- (void)swizzle_removeFromSuperview {
|
||||
UIView* oldSuperview = self.superview;
|
||||
// Be careful that we always call the swizzled implementation
|
||||
// before any early returns or mischief below!
|
||||
[self swizzle_removeFromSuperview];
|
||||
|
||||
if (oldSuperview) {
|
||||
[[SKInvalidation sharedInstance].delegate invalidateNode:oldSuperview];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface SKHiddenWindow : UIWindow
|
||||
@end
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#if FB_SONARKIT_ENABLED
|
||||
|
||||
#import "SKHiddenWindow.h"
|
||||
|
||||
@implementation SKHiddenWindow
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/*
|
||||
A hash function is needed in order to use NSObject classes
|
||||
as keys in C++ STL
|
||||
*/
|
||||
class SKObjectHash {
|
||||
public:
|
||||
size_t operator()(const NSObject* x) const {
|
||||
return (size_t)[x hash];
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
void swizzleMethods(Class cls, SEL original, SEL swissled);
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#if FB_SONARKIT_ENABLED
|
||||
|
||||
#import "SKSwizzle.h"
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
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));
|
||||
|
||||
if (didAddMethod) {
|
||||
class_replaceMethod(
|
||||
cls,
|
||||
swissled,
|
||||
method_getImplementation(originalMethod),
|
||||
method_getTypeEncoding(originalMethod));
|
||||
} else {
|
||||
method_exchangeImplementations(originalMethod, swissledMethod);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#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_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; \
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import <FlipperKitLayoutHelpers/SKNodeDescriptor.h>
|
||||
|
||||
@class SKDescriptorMapper;
|
||||
|
||||
@interface SKApplicationDescriptor : SKNodeDescriptor<UIApplication*>
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#if FB_SONARKIT_ENABLED
|
||||
|
||||
#import "SKApplicationDescriptor.h"
|
||||
|
||||
#import <FlipperKitLayoutHelpers/SKHiddenWindow.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@implementation SKApplicationDescriptor
|
||||
|
||||
- (NSString*)identifierForNode:(UIApplication*)node {
|
||||
return [NSString stringWithFormat:@"%p", node];
|
||||
}
|
||||
|
||||
- (NSUInteger)childCountForNode:(UIApplication*)node {
|
||||
return [[self visibleChildrenForNode:node] count];
|
||||
}
|
||||
|
||||
- (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)hitTest:(SKTouch*)touch forNode:(UIApplication*)node {
|
||||
bool finish = true;
|
||||
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];
|
||||
finish = false;
|
||||
}
|
||||
}
|
||||
if (finish) {
|
||||
[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")]) {
|
||||
continue;
|
||||
}
|
||||
[children addObject:window];
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import <FlipperKitLayoutHelpers/SKNodeDescriptor.h>
|
||||
|
||||
@class UIButton;
|
||||
@class SKDescriptorMapper;
|
||||
|
||||
@interface SKButtonDescriptor : SKNodeDescriptor<UIButton*>
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#if FB_SONARKIT_ENABLED
|
||||
|
||||
#import "SKButtonDescriptor.h"
|
||||
|
||||
#import <FlipperKitLayoutHelpers/SKObject.h>
|
||||
#import <FlipperKitLayoutHelpers/UIColor+SKSonarValueCoder.h>
|
||||
|
||||
@implementation SKButtonDescriptor
|
||||
|
||||
- (NSString*)identifierForNode:(UIButton*)node {
|
||||
return [NSString stringWithFormat:@"%p", node];
|
||||
}
|
||||
|
||||
- (NSUInteger)childCountForNode:(UIButton*)node {
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (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];
|
||||
|
||||
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];
|
||||
}
|
||||
,
|
||||
@"UIButton.currentTitleColor": ^(NSNumber *newValue) {
|
||||
[node setTitleColor: [UIColor fromSonarValue: newValue] forState: node.state];
|
||||
},
|
||||
@"UIButton.highlighted": ^(NSNumber *highlighted) {
|
||||
[node setHighlighted: [highlighted boolValue]];
|
||||
},
|
||||
@"UIButton.enabled": ^(NSNumber *enabled) {
|
||||
[node setEnabled: [enabled boolValue]];
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
SKNodeDescriptor* viewDescriptor = [self descriptorForClass:[UIView class]];
|
||||
NSDictionary* viewMutations = [viewDescriptor dataMutationsForNode:node];
|
||||
|
||||
NSMutableDictionary* mutations = [NSMutableDictionary new];
|
||||
[mutations addEntriesFromDictionary:buttonMutations];
|
||||
[mutations addEntriesFromDictionary:viewMutations];
|
||||
|
||||
return mutations;
|
||||
}
|
||||
|
||||
- (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)hitTest:(SKTouch*)touch forNode:(UIButton*)node {
|
||||
[touch finish];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import <FlipperKitLayoutHelpers/SKNodeDescriptor.h>
|
||||
|
||||
@class SKDescriptorMapper;
|
||||
|
||||
@interface SKScrollViewDescriptor : SKNodeDescriptor<UIScrollView*>
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#if FB_SONARKIT_ENABLED
|
||||
|
||||
#import "SKScrollViewDescriptor.h"
|
||||
|
||||
@implementation SKScrollViewDescriptor
|
||||
|
||||
- (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];
|
||||
}
|
||||
|
||||
- (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]];
|
||||
return [descriptor dataForNode:node];
|
||||
}
|
||||
|
||||
- (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];
|
||||
}
|
||||
|
||||
- (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 {
|
||||
bool finish = true;
|
||||
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 (child.view.isHidden) {
|
||||
continue;
|
||||
}
|
||||
|
||||
frame = child.view.frame;
|
||||
} else {
|
||||
UIView* child = (UIView*)childNode;
|
||||
if (child.isHidden) {
|
||||
continue;
|
||||
}
|
||||
|
||||
frame = child.frame;
|
||||
}
|
||||
|
||||
frame.origin.x -= node.contentOffset.x;
|
||||
frame.origin.y -= node.contentOffset.y;
|
||||
|
||||
if ([touch containedIn:frame]) {
|
||||
[touch continueWithChildIndex:index withOffset:frame.origin];
|
||||
finish = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (finish) {
|
||||
[touch finish];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#if FB_SONARKIT_ENABLED
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import <FlipperKitLayoutHelpers/SKNodeDescriptor.h>
|
||||
|
||||
@class SKDescriptorMapper;
|
||||
|
||||
@interface SKViewControllerDescriptor : SKNodeDescriptor<UIViewController*>
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#if FB_SONARKIT_ENABLED
|
||||
|
||||
#import "SKViewControllerDescriptor.h"
|
||||
|
||||
@implementation SKViewControllerDescriptor
|
||||
|
||||
- (NSString*)identifierForNode:(UIViewController*)node {
|
||||
return [NSString stringWithFormat:@"%p", node];
|
||||
}
|
||||
|
||||
- (NSUInteger)childCountForNode:(UIViewController*)node {
|
||||
return 1;
|
||||
}
|
||||
|
||||
- (id)childForNode:(UIViewController*)node atIndex:(NSUInteger)index {
|
||||
return node.view;
|
||||
}
|
||||
|
||||
- (void)setHighlightedForNode:(UIViewController*)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)hitTest:(SKTouch*)touch forNode:(UIViewController*)node {
|
||||
[touch continueWithChildIndex:0 withOffset:(CGPoint){0, 0}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#if FB_SONARKIT_ENABLED
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import <FlipperKitLayoutHelpers/SKNodeDescriptor.h>
|
||||
|
||||
@class SKDescriptorMapper;
|
||||
|
||||
@interface SKViewDescriptor : SKNodeDescriptor<UIView*>
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,670 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#if FB_SONARKIT_ENABLED
|
||||
|
||||
#import "SKViewDescriptor.h"
|
||||
|
||||
#import <FlipperKitHighlightOverlay/SKHighlightOverlay.h>
|
||||
#import <FlipperKitLayoutHelpers/FlipperKitLayoutDescriptorMapperProtocol.h>
|
||||
#import <FlipperKitLayoutHelpers/SKHiddenWindow.h>
|
||||
#import <FlipperKitLayoutHelpers/SKNamed.h>
|
||||
#import <FlipperKitLayoutHelpers/SKObject.h>
|
||||
#import <FlipperKitLayoutHelpers/SKYogaKitHelper.h>
|
||||
#import <FlipperKitLayoutHelpers/UIColor+SKSonarValueCoder.h>
|
||||
#import <YogaKit/UIView+Yoga.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;
|
||||
|
||||
- (instancetype)initWithDescriptorMapper:
|
||||
(id<SKDescriptorMapperProtocol>)mapper {
|
||||
if (self = [super initWithDescriptorMapper:mapper]) {
|
||||
initEnumDictionaries();
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString*)identifierForNode:(UIView*)node {
|
||||
return [NSString stringWithFormat:@"%p", node];
|
||||
}
|
||||
|
||||
- (NSUInteger)childCountForNode:(UIView*)node {
|
||||
return [[self validChildrenForNode:node] count];
|
||||
}
|
||||
|
||||
- (id)childForNode:(UIView*)node atIndex:(NSUInteger)index {
|
||||
return [[self validChildrenForNode:node] objectAtIndex:index];
|
||||
}
|
||||
|
||||
- (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]];
|
||||
|
||||
if (!child.isHidden) {
|
||||
if (responderIsUIViewController &&
|
||||
child.nextResponder != node.nextResponder) {
|
||||
[validChildren addObject:child.nextResponder];
|
||||
} else {
|
||||
[validChildren addObject:child];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)]),
|
||||
}],
|
||||
nil];
|
||||
}
|
||||
|
||||
- (NSDictionary<NSString*, SKNodeUpdateData>*)dataMutationsForNode:
|
||||
(UIView*)node {
|
||||
NSDictionary<NSString*, SKNodeUpdateData>* dataMutations = @{
|
||||
// UIView
|
||||
@"UIView.alpha" : ^(NSNumber* value){
|
||||
node.alpha = [value floatValue];
|
||||
}
|
||||
,
|
||||
@"UIView.backgroundColor": ^(NSNumber *value) {
|
||||
node.backgroundColor = [UIColor fromSonarValue: value];
|
||||
},
|
||||
@"UIView.frame.origin.y": ^(NSNumber *value) {
|
||||
CGRect frame = node.frame;
|
||||
frame.origin.y = [value floatValue];
|
||||
node.frame = frame;
|
||||
},
|
||||
@"UIView.frame.origin.x": ^(NSNumber *value) {
|
||||
CGRect frame = node.frame;
|
||||
frame.origin.x = [value floatValue];
|
||||
node.frame = frame;
|
||||
},
|
||||
@"UIView.frame.size.width": ^(NSNumber *value) {
|
||||
CGRect frame = node.frame;
|
||||
frame.size.width = [value floatValue];
|
||||
node.frame = frame;
|
||||
},
|
||||
@"UIView.frame.size.height": ^(NSNumber *value) {
|
||||
CGRect frame = node.frame;
|
||||
frame.size.width = [value floatValue];
|
||||
node.frame = frame;
|
||||
},
|
||||
// CALayer
|
||||
@"CALayer.shadowColor": ^(NSNumber *value) {
|
||||
node.layer.shadowColor = [UIColor fromSonarValue:value].CGColor;
|
||||
},
|
||||
@"CALayer.shadowOpacity": ^(NSNumber *value) {
|
||||
node.layer.shadowOpacity = [value floatValue];
|
||||
},
|
||||
@"CALayer.shadowRadius": ^(NSNumber *value) {
|
||||
node.layer.shadowRadius = [value floatValue];
|
||||
},
|
||||
@"CALayer.shadowOffset.width": ^(NSNumber *value) {
|
||||
CGSize offset = node.layer.shadowOffset;
|
||||
offset.width = [value floatValue];
|
||||
node.layer.shadowOffset = offset;
|
||||
},
|
||||
@"CALayer.shadowOffset.height": ^(NSNumber *value) {
|
||||
CGSize offset = node.layer.shadowOffset;
|
||||
offset.height = [value floatValue];
|
||||
node.layer.shadowOffset = offset;
|
||||
},
|
||||
@"CALayer.backgroundColor": ^(NSNumber *value) {
|
||||
node.layer.backgroundColor = [UIColor fromSonarValue:value].CGColor;
|
||||
},
|
||||
@"CALayer.borderColor": ^(NSNumber *value) {
|
||||
node.layer.borderColor = [UIColor fromSonarValue:value].CGColor;
|
||||
},
|
||||
@"CALayer.borderWidth": ^(NSNumber *value) {
|
||||
node.layer.borderWidth = [value floatValue];
|
||||
},
|
||||
@"CALayer.cornerRadius": ^(NSNumber *value) {
|
||||
node.layer.cornerRadius = [value floatValue];
|
||||
},
|
||||
@"CALayer.masksToBounds": ^(NSNumber *value) {
|
||||
node.layer.masksToBounds = [value boolValue];
|
||||
},
|
||||
// YGLayout
|
||||
@"YGLayout.direction": APPLY_ENUM_TO_YOGA_PROPERTY(direction, YGDirection),
|
||||
@"YGLayout.justifyContent": APPLY_ENUM_TO_YOGA_PROPERTY(justifyContent, YGJustify),
|
||||
@"YGLayout.aligns.alignContent": APPLY_ENUM_TO_YOGA_PROPERTY(alignContent, YGAlign),
|
||||
@"YGLayout.aligns.alignItems": APPLY_ENUM_TO_YOGA_PROPERTY(alignItems, YGAlign),
|
||||
@"YGLayout.aligns.alignSelf": APPLY_ENUM_TO_YOGA_PROPERTY(alignSelf, YGAlign),
|
||||
@"YGLayout.position.type": APPLY_ENUM_TO_YOGA_PROPERTY(position, YGPositionType),
|
||||
@"YGLayout.position.left.value": APPLY_VALUE_TO_YGVALUE(left),
|
||||
@"YGLayout.position.left.unit": APPLY_UNIT_TO_YGVALUE(left, YGUnit),
|
||||
@"YGLayout.position.top.value": APPLY_VALUE_TO_YGVALUE(top),
|
||||
@"YGLayout.position.top.unit": APPLY_UNIT_TO_YGVALUE(top, YGUnit),
|
||||
@"YGLayout.position.right.value": APPLY_VALUE_TO_YGVALUE(right),
|
||||
@"YGLayout.position.right.unit": APPLY_UNIT_TO_YGVALUE(right, YGUnit),
|
||||
@"YGLayout.position.bottom.value": APPLY_VALUE_TO_YGVALUE(bottom),
|
||||
@"YGLayout.position.bottom.unit": APPLY_UNIT_TO_YGVALUE(bottom, YGUnit),
|
||||
@"YGLayout.position.start.value": APPLY_VALUE_TO_YGVALUE(start),
|
||||
@"YGLayout.position.start.unit": APPLY_UNIT_TO_YGVALUE(start, YGUnit),
|
||||
@"YGLayout.position.end.value": APPLY_VALUE_TO_YGVALUE(end),
|
||||
@"YGLayout.position.end.unit": APPLY_UNIT_TO_YGVALUE(end, YGUnit),
|
||||
@"YGLayout.overflow": APPLY_ENUM_TO_YOGA_PROPERTY(overflow, YGOverflow),
|
||||
@"YGLayout.display": APPLY_ENUM_TO_YOGA_PROPERTY(display, YGDisplay),
|
||||
@"YGLayout.flex.flexDirection": APPLY_ENUM_TO_YOGA_PROPERTY(flexDirection, YGFlexDirection),
|
||||
@"YGLayout.flex.flexWrap": APPLY_ENUM_TO_YOGA_PROPERTY(flexWrap, YGWrap),
|
||||
@"YGLayout.flex.flexGrow": ^(NSNumber *value) {
|
||||
node.yoga.flexGrow = [value floatValue];
|
||||
},
|
||||
@"YGLayout.flex.flexShrink": ^(NSNumber *value) {
|
||||
node.yoga.flexShrink = [value floatValue];
|
||||
},
|
||||
@"YGLayout.flex.flexBasis.value": APPLY_VALUE_TO_YGVALUE(flexBasis),
|
||||
@"YGLayout.flex.flexBasis.unit": APPLY_UNIT_TO_YGVALUE(flexBasis, YGUnit),
|
||||
@"YGLayout.margin.left.value": APPLY_VALUE_TO_YGVALUE(marginLeft),
|
||||
@"YGLayout.margin.left.unit": APPLY_UNIT_TO_YGVALUE(marginLeft, YGUnit),
|
||||
@"YGLayout.margin.top.value": APPLY_VALUE_TO_YGVALUE(marginTop),
|
||||
@"YGLayout.margin.top.unit": APPLY_UNIT_TO_YGVALUE(marginTop, YGUnit),
|
||||
@"YGLayout.margin.right.value": APPLY_VALUE_TO_YGVALUE(marginRight),
|
||||
@"YGLayout.margin.right.unit": APPLY_UNIT_TO_YGVALUE(marginRight, YGUnit),
|
||||
@"YGLayout.margin.bottom.value": APPLY_VALUE_TO_YGVALUE(marginBottom),
|
||||
@"YGLayout.margin.bottom.unit": APPLY_UNIT_TO_YGVALUE(marginBottom, YGUnit),
|
||||
@"YGLayout.margin.start.value": APPLY_VALUE_TO_YGVALUE(marginStart),
|
||||
@"YGLayout.margin.start.unit": APPLY_UNIT_TO_YGVALUE(marginStart, YGUnit),
|
||||
@"YGLayout.margin.end.value": APPLY_VALUE_TO_YGVALUE(marginEnd),
|
||||
@"YGLayout.margin.end.unit": APPLY_UNIT_TO_YGVALUE(marginEnd, YGUnit),
|
||||
@"YGLayout.margin.horizontal.value": APPLY_VALUE_TO_YGVALUE(marginHorizontal),
|
||||
@"YGLayout.margin.horizontal.unit": APPLY_UNIT_TO_YGVALUE(marginHorizontal, YGUnit),
|
||||
@"YGLayout.margin.vertical.value": APPLY_VALUE_TO_YGVALUE(marginVertical),
|
||||
@"YGLayout.margin.vertical.unit": APPLY_UNIT_TO_YGVALUE(marginVertical, YGUnit),
|
||||
@"YGLayout.margin.all.value": APPLY_VALUE_TO_YGVALUE(margin),
|
||||
@"YGLayout.margin.all.unit": APPLY_UNIT_TO_YGVALUE(margin, YGUnit),
|
||||
@"YGLayout.padding.left.value": APPLY_VALUE_TO_YGVALUE(paddingLeft),
|
||||
@"YGLayout.padding.left.unit": APPLY_UNIT_TO_YGVALUE(paddingLeft, YGUnit),
|
||||
@"YGLayout.padding.top.value": APPLY_VALUE_TO_YGVALUE(paddingTop),
|
||||
@"YGLayout.padding.top.unit": APPLY_UNIT_TO_YGVALUE(paddingTop, YGUnit),
|
||||
@"YGLayout.padding.right.value": APPLY_VALUE_TO_YGVALUE(paddingRight),
|
||||
@"YGLayout.padding.right.unit": APPLY_UNIT_TO_YGVALUE(paddingRight, YGUnit),
|
||||
@"YGLayout.padding.bottom.value": APPLY_VALUE_TO_YGVALUE(paddingBottom),
|
||||
@"YGLayout.padding.bottom.unit": APPLY_UNIT_TO_YGVALUE(paddingBottom, YGUnit),
|
||||
@"YGLayout.padding.start.value": APPLY_VALUE_TO_YGVALUE(paddingStart),
|
||||
@"YGLayout.padding.start.unit": APPLY_UNIT_TO_YGVALUE(paddingStart, YGUnit),
|
||||
@"YGLayout.padding.end.value": APPLY_VALUE_TO_YGVALUE(paddingEnd),
|
||||
@"YGLayout.padding.end.unit": APPLY_UNIT_TO_YGVALUE(paddingEnd, YGUnit),
|
||||
@"YGLayout.padding.horizontal.value": APPLY_VALUE_TO_YGVALUE(paddingHorizontal),
|
||||
@"YGLayout.padding.horizontal.unit": APPLY_UNIT_TO_YGVALUE(paddingHorizontal, YGUnit),
|
||||
@"YGLayout.padding.vertical.value": APPLY_VALUE_TO_YGVALUE(paddingVertical),
|
||||
@"YGLayout.padding.vertical.unit": APPLY_UNIT_TO_YGVALUE(paddingVertical, YGUnit),
|
||||
@"YGLayout.padding.all.value": APPLY_VALUE_TO_YGVALUE(padding),
|
||||
@"YGLayout.padding.all.unit": APPLY_UNIT_TO_YGVALUE(padding, YGUnit),
|
||||
@"YGLayout.border.leftWidth": ^(NSNumber *value) {
|
||||
node.yoga.borderLeftWidth = [value floatValue];
|
||||
},
|
||||
@"YGLayout.border.topWidth": ^(NSNumber *value) {
|
||||
node.yoga.borderTopWidth = [value floatValue];
|
||||
},
|
||||
@"YGLayout.border.rightWidth": ^(NSNumber *value) {
|
||||
node.yoga.borderRightWidth = [value floatValue];
|
||||
},
|
||||
@"YGLayout.border.bottomWidth": ^(NSNumber *value) {
|
||||
node.yoga.borderBottomWidth = [value floatValue];
|
||||
},
|
||||
@"YGLayout.border.startWidth": ^(NSNumber *value) {
|
||||
node.yoga.borderStartWidth = [value floatValue];
|
||||
},
|
||||
@"YGLayout.border.endWidth": ^(NSNumber *value) {
|
||||
node.yoga.borderEndWidth = [value floatValue];
|
||||
},
|
||||
@"YGLayout.border.all": ^(NSNumber *value) {
|
||||
node.yoga.borderWidth = [value floatValue];
|
||||
},
|
||||
@"YGLayout.dimensions.width.value": APPLY_VALUE_TO_YGVALUE(width),
|
||||
@"YGLayout.dimensions.width.unit": APPLY_UNIT_TO_YGVALUE(width, YGUnit),
|
||||
@"YGLayout.dimensions.height.value": APPLY_VALUE_TO_YGVALUE(height),
|
||||
@"YGLayout.dimensions.height.unit": APPLY_UNIT_TO_YGVALUE(height, YGUnit),
|
||||
@"YGLayout.dimensions.minWidth.value": APPLY_VALUE_TO_YGVALUE(minWidth),
|
||||
@"YGLayout.dimensions.minWidth.unit": APPLY_UNIT_TO_YGVALUE(minWidth, YGUnit),
|
||||
@"YGLayout.dimensions.minHeight.value": APPLY_VALUE_TO_YGVALUE(minHeight),
|
||||
@"YGLayout.dimensions.minHeight.unit": APPLY_UNIT_TO_YGVALUE(minHeight, YGUnit),
|
||||
@"YGLayout.dimensions.maxWidth.value": APPLY_VALUE_TO_YGVALUE(maxWidth),
|
||||
@"YGLayout.dimensions.maxWidth.unit": APPLY_UNIT_TO_YGVALUE(maxWidth, YGUnit),
|
||||
@"YGLayout.dimensions.maxHeight.value": APPLY_VALUE_TO_YGVALUE(maxHeight),
|
||||
@"YGLayout.dimensions.maxHeight.unit": APPLY_UNIT_TO_YGVALUE(maxHeight, YGUnit),
|
||||
@"YGLayout.aspectRatio": ^(NSNumber *value) {
|
||||
node.yoga.aspectRatio = [value floatValue];
|
||||
},
|
||||
// Accessibility
|
||||
@"Accessibility.isAccessibilityElement": ^(NSNumber *value) {
|
||||
node.isAccessibilityElement = [value boolValue];
|
||||
},
|
||||
@"Accessibility.accessibilityLabel": ^(NSString *value) {
|
||||
node.accessibilityLabel = value;
|
||||
},
|
||||
@"Accessibility.accessibilityValue": ^(NSString *value) {
|
||||
node.accessibilityValue = value;
|
||||
},
|
||||
@"Accessibility.accessibilityHint": ^(NSString *value) {
|
||||
node.accessibilityHint = value;
|
||||
},
|
||||
@"Accessibility.accessibilityTraits.UIAccessibilityTraitButton": ^(NSNumber *value) {
|
||||
node.accessibilityTraits = AccessibilityTraitsToggle(node.accessibilityTraits, UIAccessibilityTraitButton, [value boolValue]);
|
||||
},
|
||||
@"Accessibility.accessibilityTraits.UIAccessibilityTraitLink": ^(NSNumber *value) {
|
||||
node.accessibilityTraits = AccessibilityTraitsToggle(node.accessibilityTraits, UIAccessibilityTraitLink, [value boolValue]);
|
||||
},
|
||||
@"Accessibility.accessibilityTraits.UIAccessibilityTraitHeader": ^(NSNumber *value) {
|
||||
node.accessibilityTraits = AccessibilityTraitsToggle(node.accessibilityTraits, UIAccessibilityTraitHeader, [value boolValue]);
|
||||
},
|
||||
@"Accessibility.accessibilityTraits.UIAccessibilityTraitSearchField": ^(NSNumber *value) {
|
||||
node.accessibilityTraits = AccessibilityTraitsToggle(node.accessibilityTraits, UIAccessibilityTraitSearchField, [value boolValue]);
|
||||
},
|
||||
@"Accessibility.accessibilityTraits.UIAccessibilityTraitImage": ^(NSNumber *value) {
|
||||
node.accessibilityTraits = AccessibilityTraitsToggle(node.accessibilityTraits, UIAccessibilityTraitImage, [value boolValue]);
|
||||
},
|
||||
@"Accessibility.accessibilityTraits.UIAccessibilityTraitSelected": ^(NSNumber *value) {
|
||||
node.accessibilityTraits = AccessibilityTraitsToggle(node.accessibilityTraits, UIAccessibilityTraitSelected, [value boolValue]);
|
||||
},
|
||||
@"Accessibility.accessibilityTraits.UIAccessibilityTraitPlaysSound": ^(NSNumber *value) {
|
||||
node.accessibilityTraits = AccessibilityTraitsToggle(node.accessibilityTraits, UIAccessibilityTraitPlaysSound, [value boolValue]);
|
||||
},
|
||||
@"Accessibility.accessibilityTraits.UIAccessibilityTraitKeyboardKey": ^(NSNumber *value) {
|
||||
node.accessibilityTraits = AccessibilityTraitsToggle(node.accessibilityTraits, UIAccessibilityTraitKeyboardKey, [value boolValue]);
|
||||
},
|
||||
@"Accessibility.accessibilityTraits.UIAccessibilityTraitStaticText": ^(NSNumber *value) {
|
||||
node.accessibilityTraits = AccessibilityTraitsToggle(node.accessibilityTraits, UIAccessibilityTraitStaticText, [value boolValue]);
|
||||
},
|
||||
@"Accessibility.accessibilityTraits.UIAccessibilityTraitSummaryElement": ^(NSNumber *value) {
|
||||
node.accessibilityTraits = AccessibilityTraitsToggle(node.accessibilityTraits, UIAccessibilityTraitSummaryElement, [value boolValue]);
|
||||
},
|
||||
@"Accessibility.accessibilityTraits.UIAccessibilityTraitNotEnabled": ^(NSNumber *value) {
|
||||
node.accessibilityTraits = AccessibilityTraitsToggle(node.accessibilityTraits, UIAccessibilityTraitNotEnabled, [value boolValue]);
|
||||
},
|
||||
@"Accessibility.accessibilityTraits.UIAccessibilityTraitUpdatesFrequently": ^(NSNumber *value) {
|
||||
node.accessibilityTraits = AccessibilityTraitsToggle(node.accessibilityTraits, UIAccessibilityTraitUpdatesFrequently, [value boolValue]);
|
||||
},
|
||||
@"Accessibility.accessibilityTraits.UIAccessibilityTraitStartsMediaSession": ^(NSNumber *value) {
|
||||
node.accessibilityTraits = AccessibilityTraitsToggle(node.accessibilityTraits, UIAccessibilityTraitStartsMediaSession, [value boolValue]);
|
||||
},
|
||||
@"Accessibility.accessibilityTraits.UIAccessibilityTraitAdjustable": ^(NSNumber *value) {
|
||||
node.accessibilityTraits = AccessibilityTraitsToggle(node.accessibilityTraits, UIAccessibilityTraitAdjustable, [value boolValue]);
|
||||
},
|
||||
@"Accessibility.accessibilityTraits.UIAccessibilityTraitAllowsDirectInteraction": ^(NSNumber *value) {
|
||||
node.accessibilityTraits = AccessibilityTraitsToggle(node.accessibilityTraits, UIAccessibilityTraitAllowsDirectInteraction, [value boolValue]);
|
||||
},
|
||||
@"Accessibility.accessibilityTraits.UIAccessibilityTraitCausesPageTurn": ^(NSNumber *value) {
|
||||
node.accessibilityTraits = AccessibilityTraitsToggle(node.accessibilityTraits, UIAccessibilityTraitCausesPageTurn, [value boolValue]);
|
||||
},
|
||||
@"Accessibility.accessibilityTraits.UIAccessibilityTraitTabBar": ^(NSNumber *value) {
|
||||
if (@available(iOS 10.0, *)) {
|
||||
node.accessibilityTraits = AccessibilityTraitsToggle(node.accessibilityTraits, UIAccessibilityTraitTabBar, [value boolValue]);
|
||||
}
|
||||
},
|
||||
@"Accessibility.accessibilityViewIsModal": ^(NSNumber *value) {
|
||||
node.accessibilityViewIsModal = [value boolValue];
|
||||
},
|
||||
@"Accessibility.shouldGroupAccessibilityChildren": ^(NSNumber *value) {
|
||||
node.shouldGroupAccessibilityChildren = [value boolValue];
|
||||
},
|
||||
}
|
||||
;
|
||||
if (@available(iOS 10.0, *)) {
|
||||
NSMutableDictionary<NSString*, SKNodeUpdateData>* latestDataMutations =
|
||||
[dataMutations mutableCopy];
|
||||
latestDataMutations
|
||||
[@"Accessibility.accessibilityTraits.UIAccessibilityTraitTabBar"] =
|
||||
^(NSNumber* value) {
|
||||
node.accessibilityTraits = AccessibilityTraitsToggle(
|
||||
node.accessibilityTraits,
|
||||
UIAccessibilityTraitTabBar,
|
||||
[value boolValue]);
|
||||
};
|
||||
dataMutations = latestDataMutations;
|
||||
}
|
||||
return dataMutations;
|
||||
}
|
||||
|
||||
- (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];
|
||||
if (highlighted == YES) {
|
||||
[overlay mountInView:node withFrame:node.bounds];
|
||||
} else {
|
||||
[overlay unmount];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)hitTest:(SKTouch*)touch forNode:(UIView*)node {
|
||||
bool finish = true;
|
||||
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;
|
||||
viewForNode = child.view;
|
||||
} else {
|
||||
viewForNode = (UIView*)childNode;
|
||||
}
|
||||
|
||||
if (viewForNode.isHidden || viewForNode.alpha <= 0 ||
|
||||
[[viewForNode class] isEqual:[SKHiddenWindow class]]) {
|
||||
/*SKHiddenWindow is the pink overlay which is added in window to capture
|
||||
the gestures.*/
|
||||
continue;
|
||||
}
|
||||
|
||||
if ([touch containedIn:viewForNode.frame]) {
|
||||
[touch continueWithChildIndex:index withOffset:viewForNode.frame.origin];
|
||||
finish = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (finish) {
|
||||
[touch finish];
|
||||
}
|
||||
}
|
||||
|
||||
static void initEnumDictionaries() {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
YGDirectionEnumMap = @{
|
||||
@(YGDirectionInherit) : @"inherit",
|
||||
@(YGDirectionLTR) : @"LTR",
|
||||
@(YGDirectionRTL) : @"RTL",
|
||||
};
|
||||
|
||||
YGFlexDirectionEnumMap = @{
|
||||
@(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",
|
||||
};
|
||||
|
||||
YGAlignEnumMap = @{
|
||||
@(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",
|
||||
};
|
||||
|
||||
YGWrapEnumMap = @{
|
||||
@(YGWrapNoWrap) : @"no-wrap",
|
||||
@(YGWrapWrap) : @"wrap",
|
||||
@(YGWrapWrapReverse) : @"wrap-reverse",
|
||||
};
|
||||
|
||||
YGOverflowEnumMap = @{
|
||||
@(YGOverflowVisible) : @"visible",
|
||||
@(YGOverflowHidden) : @"hidden",
|
||||
@(YGOverflowScroll) : @"scroll",
|
||||
};
|
||||
|
||||
YGDisplayEnumMap = @{
|
||||
@(YGDisplayFlex) : @"flex",
|
||||
@(YGDisplayNone) : @"none",
|
||||
};
|
||||
|
||||
YGUnitEnumMap = @{
|
||||
@(YGUnitUndefined) : @"undefined",
|
||||
@(YGUnitPoint) : @"point",
|
||||
@(YGUnitPercent) : @"percent",
|
||||
@(YGUnitAuto) : @"auto",
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
static NSDictionary* SKYGValueObject(YGValue value) {
|
||||
return @{
|
||||
@"value" : SKMutableObject(@(value.value)),
|
||||
@"unit" : SKMutableObject(YGUnitEnumMap[@(value.unit)]),
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
Takes the originalTraits, and set all bits from toggleTraits to the toggleValue
|
||||
e.g. originalTraits = UIAccessibilityTraitButton | UIAccessibilityTraitSelected
|
||||
toggleTraits = UIAccessibilityTraitImage
|
||||
toggleValue = YES
|
||||
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;
|
||||
return (originalTraits & ~(toggleTraits)) | bitsValue;
|
||||
}
|
||||
|
||||
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))),
|
||||
}];
|
||||
if (@available(iOS 10.0, *)) {
|
||||
traitsDict[@"UIAccessibilityTraitTabBar"] = SKMutableObject(
|
||||
@(!!(accessibilityTraits & UIAccessibilityTraitTabBar)));
|
||||
}
|
||||
return traitsDict;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user