Summary: Move UIDebugger plugin to OSS space.

Reviewed By: passy

Differential Revision: D47634848

fbshipit-source-id: 90e8c0181a2434d0e5d76bdb99b902051e6d702e
This commit is contained in:
Lorenzo Blasa
2023-07-21 04:47:13 -07:00
committed by Facebook GitHub Bot
parent af5b9532ec
commit db7aa9eeaf
134 changed files with 6368 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class UIDFrameworkEventMetadata;
@class UIDFrameworkEvent;
@protocol UIDFrameworkEventManager<NSObject>
- (void)registerEventMetadata:(UIDFrameworkEventMetadata*)eventMetadata;
- (void)emitEvent:(UIDFrameworkEvent*)event;
- (NSArray<UIDFrameworkEventMetadata*>*)eventsMetadata;
- (NSArray<UIDFrameworkEvent*>*)events;
- (void)enable;
- (void)disable;
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,21 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <Foundation/Foundation.h>
#import "UIDFrameworkEventManager.h"
NS_ASSUME_NONNULL_BEGIN
@interface UIDSerialFrameworkEventManager : NSObject<UIDFrameworkEventManager>
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,75 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDSerialFrameworkEventManager.h"
@interface UIDSerialFrameworkEventManager () {
dispatch_queue_t _queue;
NSMutableArray<UIDFrameworkEventMetadata*>* _eventMetadata;
NSMutableArray<UIDFrameworkEvent*>* _events;
BOOL _enabled;
}
@end
@implementation UIDSerialFrameworkEventManager
- (instancetype)init {
if (self = [super init]) {
_enabled = false;
_eventMetadata = [NSMutableArray new];
_events = [NSMutableArray new];
_queue = dispatch_queue_create(
"ui-debugger.framework-events", DISPATCH_QUEUE_SERIAL);
}
return self;
}
- (void)emitEvent:(nonnull UIDFrameworkEvent*)event {
dispatch_async(_queue, ^{
if (self->_enabled) {
[self->_events addObject:event];
}
});
}
- (void)registerEventMetadata:
(nonnull UIDFrameworkEventMetadata*)eventMetadata {
[_eventMetadata addObject:eventMetadata];
}
- (NSArray<UIDFrameworkEventMetadata*>*)eventsMetadata {
return [_eventMetadata copy];
}
- (NSArray<UIDFrameworkEvent*>*)events {
__block NSArray* events = nil;
dispatch_sync(_queue, ^{
events = [_events copy];
[_events removeAllObjects];
});
return events ?: @[];
}
- (void)enable {
dispatch_async(_queue, ^{
self->_enabled = true;
});
}
- (void)disable {
dispatch_async(_queue, ^{
self->_enabled = false;
[self->_events removeAllObjects];
});
}
@end
#endif

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <FlipperKit/FlipperConnection.h>
#import <Foundation/Foundation.h>
#import "UIDFrameworkEventManager.h"
#import "UIDUpdateDigester.h"
NS_ASSUME_NONNULL_BEGIN
@class UIDDescriptorRegister;
@class UIDTreeObserverFactory;
@class UIDFrameworkEvent;
@class UIDFrameworkEventMetadata;
@interface UIDContext : NSObject
@property(nonatomic, nullable) UIApplication* application;
@property(nonatomic, nullable) id<FlipperConnection> connection;
@property(nonatomic, readonly) UIDDescriptorRegister* descriptorRegister;
@property(nonatomic, readonly) UIDTreeObserverFactory* observerFactory;
@property(nonatomic, nullable) id<UIDUpdateDigester> updateDigester;
@property(nonatomic, strong, readonly) id<UIDFrameworkEventManager>
frameworkEventManager;
- (instancetype)initWithApplication:(UIApplication*)application
descriptorRegister:(UIDDescriptorRegister*)descriptorRegister
observerFactory:(UIDTreeObserverFactory*)observerFactory;
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDContext.h"
#import "UIDDescriptorRegister.h"
#import "UIDSerialFrameworkEventManager.h"
#import "UIDTreeObserverFactory.h"
@implementation UIDContext
- (instancetype)initWithApplication:(UIApplication*)application
descriptorRegister:(UIDDescriptorRegister*)descriptorRegister
observerFactory:(UIDTreeObserverFactory*)observerFactory {
self = [super init];
if (self) {
_application = application;
_descriptorRegister = descriptorRegister;
_observerFactory = observerFactory;
_connection = nil;
_frameworkEventManager = [UIDSerialFrameworkEventManager new];
}
return self;
}
@end
#endif

View File

@@ -0,0 +1,31 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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>
NS_ASSUME_NONNULL_BEGIN
@protocol UIDUpdate
@end
@interface UIDSubtreeUpdate : NSObject<UIDUpdate>
@property(nonatomic) NSString* observerType;
@property(nonatomic) NSUInteger rootId;
@property(nonatomic) NSArray* nodes;
@property(nonatomic) NSTimeInterval timestamp;
@property(nonatomic) long traversalMS;
@property(nonatomic) long snapshotMS;
@property(nonatomic) UIImage* snapshot;
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,15 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDUpdate.h"
@implementation UIDSubtreeUpdate
@end
#endif

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <Foundation/Foundation.h>
#import "UIDUpdate.h"
NS_ASSUME_NONNULL_BEGIN
@protocol UIDUpdateDigester
- (void)digest:(id<UIDUpdate>)update;
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,52 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <Foundation/Foundation.h>
#import "UIDNodeDescriptor.h"
NS_ASSUME_NONNULL_BEGIN
/**
A chained descriptor is a special type of descriptor that models the
inheritance hierarchy in native UI frameworks. With this setup you can define
a descriptor for each class in the inheritance chain and given that we record
the super class's descriptor we can automatically aggregate the results for
each descriptor in the inheritance hierarchy in a chain.
The result is that each descriptor in the inheritance chain only exports the
attributes that it knows about but we still get all the attributes from the
parent classes.
*/
@interface UIDChainedDescriptor<__covariant T> : UIDNodeDescriptor<T>
@property(strong, nonatomic) UIDChainedDescriptor* parent;
/** The children this node exposes in the inspector. */
- (NSArray<id<NSObject>>*)aggregateChildrenOfNode:(T)node;
/**
Get the attributes to show for this node in the sidebar of the inspector. The
object will be shown in order and with a header matching the given name.
*/
- (void)aggregateAttributes:(UIDMutableAttributes*)attributes forNode:(id)node;
/**
These are shown inline in the tree view on the desktop, will likely be removed
in the future.
*/
- (void)aggregateInlineAttributes:(UIDMutableInlineAttributes*)attributes
forNode:(id)node;
- (NSSet<NSString*>*)aggregateTagsForNode:(id)node;
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,87 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDChainedDescriptor.h"
#import "UIDInspectable.h"
@implementation UIDChainedDescriptor
- (NSSet<NSString*>*)tagsForNode:(id)node {
NSSet* tags = [self aggregateTagsForNode:node] ?: [_parent tagsForNode:node];
return tags ?: [NSSet set];
}
- (NSSet<NSString*>*)aggregateTagsForNode:(id)node {
return nil;
}
- (UIDBounds*)boundsForNode:(id)node {
return [_parent boundsForNode:node];
}
- (id<NSObject>)activeChildForNode:(id)node {
return [_parent activeChildForNode:node];
}
- (UIImage*)snapshotForNode:(id)node {
return [_parent snapshotForNode:node];
}
- (NSArray<id<NSObject>>*)childrenOfNode:(id)node {
NSArray<id<NSObject>>* children = [self aggregateChildrenOfNode:node];
if (!children) {
children = [_parent childrenOfNode:node];
}
return children != NULL ? children : [NSArray array];
}
- (NSArray<id<NSObject>>*)aggregateChildrenOfNode:(id)node {
return nil;
}
- (UIDAttributes*)attributesForNode:(id)node {
UIDMutableAttributes* attributes = [NSMutableDictionary new];
[self aggregateAttributes:attributes forNode:node];
UIDChainedDescriptor* currentDescriptor = _parent;
while (currentDescriptor) {
[currentDescriptor aggregateAttributes:attributes forNode:node];
currentDescriptor = currentDescriptor.parent;
}
return attributes;
}
- (void)aggregateAttributes:(UIDMutableAttributes*)attributes forNode:(id)node {
}
- (UIDInlineAttributes*)inlineAttributesForNode:(id)node {
UIDMutableInlineAttributes* attributes = [NSMutableDictionary new];
[attributes addEntriesFromDictionary:[super inlineAttributesForNode:node]];
[self aggregateInlineAttributes:attributes forNode:node];
UIDChainedDescriptor* currentDescriptor = _parent;
while (currentDescriptor) {
[currentDescriptor aggregateInlineAttributes:attributes forNode:node];
currentDescriptor = currentDescriptor.parent;
}
return attributes;
}
- (void)aggregateInlineAttributes:(UIDMutableInlineAttributes*)attributes
forNode:(id)node {
}
@end
#endif

View File

@@ -0,0 +1,69 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDBounds.h"
#import "UIDInspectable.h"
NS_ASSUME_NONNULL_BEGIN
@protocol UIDDescriptor<NSObject>
/**
A globally unique ID used to identify a node in the hierarchy.
*/
- (NSUInteger)UID_identifier;
/**
The name used to identify this node in the inspector. Does not need to be
unique. A good default is to use the class name of the node.
*/
- (NSString*)UID_name;
/**
Get the attributes to show for this node in the sidebar of the inspector. The
object will be shown in order and with a header matching the given name.
*/
- (void)UID_aggregateAttributes:(UIDMutableAttributes*)attributes;
@optional
/**
These are shown inline in the tree view on the desktop, will likely be removed
in the future.
*/
- (UIDInlineAttributes*)UID_inlineAttributes;
/** The children this node exposes in the inspector. */
- (NSArray<id<NSObject>>*)UID_children;
/** Should be w.r.t the direct parent */
- (UIDBounds*)UID_bounds;
/**
If the type has the concept of overlapping children, then this indicates
which child is active / on top, we will only listen to / traverse this child.
If return null we assume all children are 'active'.
*/
- (id<NSObject>)UID_activeChild;
/** Get a snapshot of the node. */
- (UIImage*)UID_snapshot;
/**
Set of tags to describe this node in an abstract way for the UI. Unfortunately
this can't be an enum as we have to plugin 3rd party frameworks dynamically.
*/
- (NSSet<NSString*>*)UID_tags;
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <Foundation/Foundation.h>
#import "UIDNodeDescriptor.h"
NS_ASSUME_NONNULL_BEGIN
@interface UIDDescriptorRegister : NSObject
+ (instancetype)defaultRegister;
- (void)registerDescriptor:(UIDNodeDescriptor*)descriptor forClass:(Class)clazz;
- (UIDNodeDescriptor*)descriptorForClass:(Class)clazz;
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,103 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDDescriptorRegister.h"
#import <objc/runtime.h>
#import "UIDChainedDescriptor.h"
#import "UIDUIApplicationDescriptor.h"
#import "UIDUILabelDescriptor.h"
#import "UIDUINavigationControllerDescriptor.h"
#import "UIDUITabBarControllerDescriptor.h"
#import "UIDUIViewControllerDescriptor.h"
#import "UIDUIViewDescriptor.h"
#import "UIDUIWindowDescriptor.h"
@interface UIDDescriptorRegister ()
- (void)prepareChain;
@end
@implementation UIDDescriptorRegister {
NSMutableDictionary<NSString*, UIDNodeDescriptor*>* _register;
}
- (instancetype)init {
self = [super init];
if (self) {
_register = [NSMutableDictionary new];
}
return self;
}
+ (instancetype)defaultRegister {
static UIDDescriptorRegister* defaultRegister = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
defaultRegister = [UIDDescriptorRegister new];
[defaultRegister registerDescriptor:[UIDUIApplicationDescriptor new]
forClass:[UIApplication class]];
[defaultRegister registerDescriptor:[UIDUIWindowDescriptor new]
forClass:[UIWindow class]];
[defaultRegister registerDescriptor:[UIDUIViewControllerDescriptor new]
forClass:[UIViewController class]];
[defaultRegister registerDescriptor:[UIDUIViewDescriptor new]
forClass:[UIView class]];
[defaultRegister registerDescriptor:[UIDUILabelDescriptor new]
forClass:[UILabel class]];
});
return defaultRegister;
}
- (void)registerDescriptor:(UIDNodeDescriptor*)descriptor
forClass:(Class)clazz {
NSString* key = NSStringFromClass(clazz);
_register[key] = descriptor;
[self prepareChain];
}
- (UIDNodeDescriptor*)descriptorForClass:(Class)clazz {
UIDNodeDescriptor* classDescriptor = nil;
while (classDescriptor == nil && clazz != nil) {
classDescriptor = [_register objectForKey:NSStringFromClass(clazz)];
clazz = [clazz superclass];
}
return classDescriptor;
}
- (void)prepareChain {
NSEnumerator* enumerator = [_register keyEnumerator];
NSString* key;
while ((key = [enumerator nextObject])) {
UIDNodeDescriptor* descriptor = [_register objectForKey:key];
if ([descriptor isKindOfClass:[UIDChainedDescriptor class]]) {
UIDChainedDescriptor* chainedDescriptor =
(UIDChainedDescriptor*)descriptor;
Class clazz = NSClassFromString(key);
Class superclass = [clazz superclass];
UIDNodeDescriptor* superDescriptor = [self descriptorForClass:superclass];
if ([superDescriptor isKindOfClass:[UIDChainedDescriptor class]]) {
chainedDescriptor.parent = (UIDChainedDescriptor*)superDescriptor;
}
}
}
}
@end
#endif

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <Foundation/Foundation.h>
#import "UIDMetadata.h"
NS_ASSUME_NONNULL_BEGIN
FOUNDATION_EXPORT NSString* const UIDEBUGGER_METADATA_TYPE_IDENTIFIER;
FOUNDATION_EXPORT NSString* const UIDEBUGGER_METADATA_TYPE_ATTRIBUTE;
FOUNDATION_EXPORT NSString* const UIDEBUGGER_METADATA_TYPE_LAYOUT;
FOUNDATION_EXPORT NSString* const UIDEBUGGER_METADATA_TYPE_DOCUMENTATION;
@interface UIDMetadataRegister : NSObject
+ (instancetype)shared;
- (UIDMetadataId)registerMetadataWithType:(NSString*)type name:(NSString*)name;
- (UIDMetadataId)registerMetadataWithType:(NSString*)type
name:(NSString*)name
isMutable:(bool)isMutable
definedBy:(UIDMetadataId)definedById;
- (NSDictionary<UIDMetadataId, UIDMetadata*>*)extractPendingMetadata;
- (UIDMetadataId)findMetadataDefinedBy:(UIDMetadataId)definedById
name:(NSString*)name;
- (UIDMetadataId)findRootMetadataWithName:(NSString*)name;
- (void)reset;
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,126 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDMetadataRegister.h"
NSString* const UIDEBUGGER_METADATA_TYPE_IDENTIFIER = @"identity";
NSString* const UIDEBUGGER_METADATA_TYPE_ATTRIBUTE = @"attribute";
NSString* const UIDEBUGGER_METADATA_TYPE_LAYOUT = @"layout";
NSString* const UIDEBUGGER_METADATA_TYPE_DOCUMENTATION = @"documentation";
typedef NSMutableDictionary<NSString*, UIDMetadata*>* UIDNamedMetadata;
@interface UIDMetadataRegister () {
NSMutableDictionary<UIDMetadataId, UIDNamedMetadata>* _register;
NSMutableArray<UIDMetadata*>* _pending;
uint32_t _generator;
UIDMetadataId _rootId;
NSLock* _lock;
}
@end
@implementation UIDMetadataRegister
- (instancetype)init {
self = [super init];
if (self) {
_lock = [NSLock new];
_register = [NSMutableDictionary new];
_pending = [NSMutableArray new];
_rootId = @0;
_generator = 0;
[_register setObject:[NSMutableDictionary new] forKey:_rootId];
}
return self;
}
+ (instancetype)shared {
static UIDMetadataRegister* instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [UIDMetadataRegister new];
});
return instance;
}
- (UIDMetadataId)registerMetadataWithType:(NSString*)type name:(NSString*)name {
return [self registerMetadataWithType:type
name:name
isMutable:false
definedBy:_rootId];
}
- (UIDMetadataId)registerMetadataWithType:(NSString*)type
name:(NSString*)name
isMutable:(bool)isMutable
definedBy:(UIDMetadataId)parent {
UIDMetadataId identifier = @(++_generator);
UIDMetadata* metadata = [[UIDMetadata alloc] initWithIdentifier:identifier
type:type
name:name
isMutable:isMutable
parent:parent];
[_lock lock];
if (![_register objectForKey:parent]) {
[_register setObject:[NSMutableDictionary new] forKey:parent];
}
[[_register objectForKey:parent] setObject:metadata forKey:name];
[_pending addObject:metadata];
[_lock unlock];
return identifier;
}
- (UIDMetadataId)findRootMetadataWithName:(NSString*)name {
return [self findMetadataDefinedBy:_rootId name:name];
}
- (UIDMetadataId)findMetadataDefinedBy:(UIDMetadataId)parentId
name:(NSString*)name {
[_lock lock];
UIDMetadata* metadata = [[_register objectForKey:parentId] objectForKey:name];
[_lock unlock];
if (metadata) {
return metadata.identifier;
}
return nil;
}
- (NSDictionary<UIDMetadataId, UIDMetadata*>*)extractPendingMetadata {
NSMutableDictionary* pendingMetadata = [NSMutableDictionary new];
[_lock lock];
for (UIDMetadata* metadata in _pending) {
[pendingMetadata setObject:metadata forKey:metadata.identifier];
}
[_pending removeAllObjects];
[_lock unlock];
return pendingMetadata;
}
- (void)reset {
[_lock lock];
[_pending removeAllObjects];
for (id key in _register) {
UIDNamedMetadata value = [_register objectForKey:key];
[_pending addObjectsFromArray:value.allValues];
}
[_lock unlock];
}
@end
#endif

View File

@@ -0,0 +1,72 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDBounds.h"
#import "UIDInspectable.h"
NS_ASSUME_NONNULL_BEGIN
@interface UIDNodeDescriptor<__covariant T> : NSObject
/**
A globally unique ID used to identify a node in the hierarchy.
*/
- (NSUInteger)identifierForNode:(T)node;
/**
The name used to identify this node in the inspector. Does not need to be
unique. A good default is to use the class name of the node.
*/
- (NSString*)nameForNode:(T)node;
/**
Get the attributes to show for this node in the sidebar of the inspector. The
object will be shown in order and with a header matching the given name.
*/
- (UIDAttributes*)attributesForNode:(T)node;
/**
These are shown inline in the tree view on the desktop, will likely be removed
in the future.
*/
- (UIDInlineAttributes*)inlineAttributesForNode:(T)node;
/**
These contain additional contextual data (currently: Bloks node metadata).
*/
- (UIDGenericAttributes*)hiddenAttributesForNode:(T)node;
/** The children this node exposes in the inspector. */
- (NSArray<id<NSObject>>*)childrenOfNode:(T)node;
/** Should be w.r.t the direct parent */
- (UIDBounds*)boundsForNode:(T)node;
/**
If the type has the concept of overlapping children, then this indicates
which child is active / on top, we will only listen to / traverse this child.
If return null we assume all children are 'active'.
*/
- (id<NSObject>)activeChildForNode:(T)node;
/** Get a snapshot of the node. */
- (UIImage*)snapshotForNode:(T)node;
/**
Set of tags to describe this node in an abstract way for the UI. Unfortunately
this can't be an enum as we have to plugin 3rd party frameworks dynamically.
*/
- (NSSet<NSString*>*)tagsForNode:(T)node;
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDNodeDescriptor.h"
@implementation UIDNodeDescriptor
- (NSUInteger)identifierForNode:(id)node {
return [node hash];
}
- (NSString*)nameForNode:(id)node {
return NSStringFromClass([node class]);
}
- (UIDInlineAttributes*)inlineAttributesForNode:(id)node {
return @{@"address" : [NSString stringWithFormat:@"%p", node]};
}
- (UIDGenericAttributes*)hiddenAttributesForNode:(id)node {
return nil;
}
- (UIDAttributes*)attributesForNode:(id)node {
return [NSDictionary dictionary];
}
- (NSArray<id<NSObject>>*)childrenOfNode:(id)node {
return [NSArray array];
}
- (NSSet<NSString*>*)tagsForNode:(id)node {
return [NSSet set];
}
- (UIDBounds*)boundsForNode:(id)node {
return nil;
}
- (id<NSObject>)activeChildForNode:(id)node {
return nil;
}
- (UIImage*)snapshotForNode:(id)node {
return nil;
}
@end
#endif

View File

@@ -0,0 +1,21 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDNodeDescriptor.h"
NS_ASSUME_NONNULL_BEGIN
@interface UIDUIApplicationDescriptor : UIDNodeDescriptor<UIApplication*>
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDUIApplicationDescriptor.h"
#import <objc/runtime.h>
#import <string>
#import <unordered_set>
#import "UIDBounds.h"
#import "UIDSnapshot.h"
@implementation UIDUIApplicationDescriptor
- (NSArray<id<NSObject>>*)childrenOfNode:(UIApplication*)node {
static std::unordered_set<std::string> ignoredWindows(
{"FBStatusBarTrackingWindow",
"FBAccessibilityOverlayWindow",
"UITextEffectsWindow"});
NSMutableArray<UIWindow*>* children = [NSMutableArray new];
for (UIWindow* window in node.windows) {
if (ignoredWindows.find(class_getName(window.class)) !=
ignoredWindows.end()) {
continue;
}
[children addObject:window];
}
return children;
}
- (id<NSObject>)activeChildForNode:(UIApplication*)node {
return node.keyWindow;
}
- (UIDBounds*)boundsForNode:(UIApplication*)node {
return [UIDBounds fromRect:[UIScreen mainScreen].bounds];
}
- (UIImage*)snapshotForNode:(UIApplication*)node {
return UIDApplicationSnapshot(node, [self childrenOfNode:node]);
}
@end
#endif

View File

@@ -0,0 +1,21 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDChainedDescriptor.h"
NS_ASSUME_NONNULL_BEGIN
@interface UIDUILabelDescriptor : UIDChainedDescriptor<UILabel*>
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,248 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDUILabelDescriptor.h"
#import "UIDInspectable.h"
#import "UIDMetadata.h"
#import "UIDMetadataRegister.h"
@interface UIDUILabelDescriptor () {
UIDMetadataId UILabelAttributeId;
UIDMetadataId TextAttributeId;
UIDMetadataId AttributedTextAttributeId;
UIDMetadataId FontAttributeId;
UIDMetadataId TextColorAttributeId;
UIDMetadataId TextAlignmentAttributeId;
UIDMetadataId LineBreakModeAttributeId;
UIDMetadataId LineBreakStrategyAttributeId;
UIDMetadataId EnabledAttributeId;
UIDMetadataId ShowExpansionTextAttributeId;
UIDMetadataId AdjustsFontSizeToFitWidthAttributeId;
UIDMetadataId AllowsDefaultTightneningForTruncationAttributeId;
UIDMetadataId BaselineAdjustmentAttributeId;
UIDMetadataId MinScaleFactorAttributeId;
UIDMetadataId NumberOfLinesAttributeId;
UIDMetadataId HighlightedTextColorAttributeId;
UIDMetadataId HighlightedAttributeId;
UIDMetadataId ShadowColorAttributeId;
UIDMetadataId ShadowOffsetAttributeId;
NSDictionary* NSTextAlignmentEnum;
NSDictionary* NSLineBreakModeEnum;
NSDictionary* NSLineBreakStrategyEnum;
NSDictionary* UIBaselineAdjustmentEnum;
}
@end
@implementation UIDUILabelDescriptor
- (instancetype)init {
self = [super init];
if (self) {
NSTextAlignmentEnum = @{
@(NSTextAlignmentLeft) : @"LEFT",
@(NSTextAlignmentRight) : @"RIGHT",
@(NSTextAlignmentCenter) : @"CENTER",
@(NSTextAlignmentJustified) : @"JUSTIFIED",
@(NSTextAlignmentNatural) : @"NATURAL",
};
NSLineBreakModeEnum = @{
@(NSLineBreakByWordWrapping) : @"WORD WRAPPING",
@(NSLineBreakByCharWrapping) : @"CHAR WRAPPING",
@(NSLineBreakByClipping) : @"CLIPPING",
@(NSLineBreakByTruncatingHead) : @"TRUNCATING HEAD",
@(NSLineBreakByTruncatingTail) : @"TRUNCATING TAIL",
@(NSLineBreakByTruncatingMiddle) : @"TRUNCATING MIDDLE",
};
if (@available(iOS 14.0, *)) {
NSLineBreakStrategyEnum = @{
@(NSLineBreakStrategyNone) : @"NONE",
@(NSLineBreakStrategyPushOut) : @"PUSH OUT",
@(NSLineBreakStrategyHangulWordPriority) : @"HANGUL WORD PRIORITY",
@(NSLineBreakStrategyStandard) : @"STANDARD",
};
} else {
NSLineBreakStrategyEnum = @{
@(NSLineBreakStrategyNone) : @"NONE",
@(NSLineBreakStrategyPushOut) : @"PUSH OUT",
};
}
UIBaselineAdjustmentEnum = @{
@(UIBaselineAdjustmentAlignBaselines) : @"ALIGN BASELINES",
@(UIBaselineAdjustmentAlignCenters) : @"ALIGN CENTERS",
@(UIBaselineAdjustmentNone) : @"NONE",
};
UILabelAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"UILabel"];
TextAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"text"
isMutable:false
definedBy:UILabelAttributeId];
AttributedTextAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"attributedText"
isMutable:false
definedBy:UILabelAttributeId];
FontAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"font"
isMutable:false
definedBy:UILabelAttributeId];
TextColorAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"textColor"
isMutable:false
definedBy:UILabelAttributeId];
TextAlignmentAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"textAlignment"
isMutable:false
definedBy:UILabelAttributeId];
LineBreakModeAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"lineBreakMode"
isMutable:false
definedBy:UILabelAttributeId];
LineBreakStrategyAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"lineBreakStrategy"
isMutable:false
definedBy:UILabelAttributeId];
EnabledAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"enabled"
isMutable:false
definedBy:UILabelAttributeId];
if (@available(iOS 15.0, macCatalyst 15.0, *)) {
ShowExpansionTextAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"showsExpansionTextWhenTruncated"
isMutable:false
definedBy:UILabelAttributeId];
}
AdjustsFontSizeToFitWidthAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"adjustsFontSizeToFitWidth"
isMutable:false
definedBy:UILabelAttributeId];
AllowsDefaultTightneningForTruncationAttributeId =
[[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"allowsDefaultTighteningForTruncation"
isMutable:false
definedBy:UILabelAttributeId];
BaselineAdjustmentAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"baselineAdjustment"
isMutable:false
definedBy:UILabelAttributeId];
MinScaleFactorAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"minimumScaleFactor"
isMutable:false
definedBy:UILabelAttributeId];
NumberOfLinesAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"numberOfLines"
isMutable:false
definedBy:UILabelAttributeId];
HighlightedTextColorAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"highlightedTextColor"
isMutable:false
definedBy:UILabelAttributeId];
HighlightedAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"highligted"
isMutable:false
definedBy:UILabelAttributeId];
ShadowColorAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"shadowColor"
isMutable:false
definedBy:UILabelAttributeId];
ShadowOffsetAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"shadowOffset"
isMutable:false
definedBy:UILabelAttributeId];
}
return self;
}
- (void)aggregateAttributes:(UIDMutableAttributes*)attributes
forNode:(UILabel*)node {
NSMutableDictionary* labelAttributes = [NSMutableDictionary new];
[labelAttributes setObject:[UIDInspectableText fromText:node.text]
forKey:TextAttributeId];
[labelAttributes
setObject:[UIDInspectableText fromText:[node.attributedText string]]
forKey:AttributedTextAttributeId];
[labelAttributes setObject:[UIDInspectableText fromText:node.font.fontName]
forKey:FontAttributeId];
[labelAttributes setObject:[UIDInspectableColor fromColor:node.textColor]
forKey:TextColorAttributeId];
[labelAttributes
setObject:[UIDInspectableEnum
from:NSTextAlignmentEnum[@(node.textAlignment)]]
forKey:TextAlignmentAttributeId];
[labelAttributes
setObject:[UIDInspectableEnum
from:NSLineBreakModeEnum[@(node.lineBreakMode)]]
forKey:LineBreakModeAttributeId];
[labelAttributes setObject:[UIDInspectableBoolean fromBoolean:node.enabled]
forKey:EnabledAttributeId];
if (@available(iOS 15.0, macCatalyst 15.0, *)) {
[labelAttributes
setObject:[UIDInspectableBoolean
fromBoolean:node.showsExpansionTextWhenTruncated]
forKey:ShowExpansionTextAttributeId];
}
[labelAttributes setObject:[UIDInspectableBoolean
fromBoolean:node.adjustsFontSizeToFitWidth]
forKey:AdjustsFontSizeToFitWidthAttributeId];
[labelAttributes
setObject:[UIDInspectableBoolean
fromBoolean:node.allowsDefaultTighteningForTruncation]
forKey:AllowsDefaultTightneningForTruncationAttributeId];
[labelAttributes
setObject:[UIDInspectableEnum
from:UIBaselineAdjustmentEnum[@(node.baselineAdjustment)]]
forKey:BaselineAdjustmentAttributeId];
[labelAttributes
setObject:[UIDInspectableNumber fromCGFloat:node.minimumScaleFactor]
forKey:MinScaleFactorAttributeId];
[labelAttributes
setObject:[UIDInspectableNumber
fromNumber:[NSNumber numberWithInt:node.numberOfLines]]
forKey:NumberOfLinesAttributeId];
[labelAttributes
setObject:[UIDInspectableColor fromColor:node.highlightedTextColor]
forKey:HighlightedTextColorAttributeId];
[labelAttributes
setObject:[UIDInspectableBoolean fromBoolean:node.highlighted]
forKey:HighlightedAttributeId];
[labelAttributes setObject:[UIDInspectableColor fromColor:node.shadowColor]
forKey:ShadowColorAttributeId];
[labelAttributes setObject:[UIDInspectableSize fromSize:node.shadowOffset]
forKey:ShadowOffsetAttributeId];
[attributes setObject:[UIDInspectableObject fromFields:labelAttributes]
forKey:UILabelAttributeId];
}
@end
#endif

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDNodeDescriptor.h"
NS_ASSUME_NONNULL_BEGIN
/**
UINavigationController
(https://developer.apple.com/documentation/uikit/uinavigationcontroller?language=objc)
Propeties:
- viewControllers: the view controllers currently on the navigation stack.
- topViewController: last controller pushed on top of the navigation
stack.
- visibleViewController: the view controller associated with the
currently visible view in the navigation stack. View Controller can also be
presented instead of pushed. If presented, then it hasn't changed the stack
even though its view is visible.
*/
@interface UIDUINavigationControllerDescriptor
: UIDNodeDescriptor<UINavigationController*>
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDUINavigationControllerDescriptor.h"
@implementation UIDUINavigationControllerDescriptor
- (NSArray<id<NSObject>>*)childrenOfNode:(UINavigationController*)node {
return node.viewControllers;
}
- (id<NSObject>)activeChildForNode:(UINavigationController*)node {
return node.visibleViewController;
}
- (UIDBounds*)boundsForNode:(UINavigationController*)node {
return [UIDBounds fromRect:node.view.bounds];
}
@end
#endif

View File

@@ -0,0 +1,31 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDNodeDescriptor.h"
NS_ASSUME_NONNULL_BEGIN
/**
UITabBarController
(https://developer.apple.com/documentation/uikit/uitabbarcontroller?language=objc)
Properties:
- viewControllers: root view controllers displayed by the tab bar user
interface.
- selectedViewController: the view controller associated with the
currently selected tab bar item.
*/
@interface UIDUITabBarControllerDescriptor
: UIDNodeDescriptor<UITabBarController*>
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDUITabBarControllerDescriptor.h"
@implementation UIDUITabBarControllerDescriptor
- (NSArray<id<NSObject>>*)childrenOfNode:(UITabBarController*)node {
return node.viewControllers;
}
- (id<NSObject>)activeChildForNode:(UITabBarController*)node {
return node.selectedViewController;
}
- (UIDBounds*)boundsForNode:(UITabBarController*)node {
return [UIDBounds fromRect:node.view.bounds];
}
@end
#endif

View File

@@ -0,0 +1,21 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDNodeDescriptor.h"
NS_ASSUME_NONNULL_BEGIN
@interface UIDUIViewControllerDescriptor : UIDNodeDescriptor<UIViewController*>
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDUIViewControllerDescriptor.h"
@implementation UIDUIViewControllerDescriptor
- (NSArray<id<NSObject>>*)childrenOfNode:(UIViewController*)node {
if (node.view != nil) {
return [NSArray arrayWithObject:node.view];
}
return [NSArray array];
}
- (UIDBounds*)boundsForNode:(UIViewController*)node {
CGRect bounds = CGRectMake(
0, 0, node.view.bounds.size.width, node.view.bounds.size.height);
return [UIDBounds fromRect:bounds];
}
@end
#endif

View File

@@ -0,0 +1,21 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDChainedDescriptor.h"
NS_ASSUME_NONNULL_BEGIN
@interface UIDUIViewDescriptor : UIDChainedDescriptor<UIView*>
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDUIViewDescriptor.h"
#import "UIView+UIDDescriptor.h"
@implementation UIDUIViewDescriptor
- (void)aggregateAttributes:(UIDMutableAttributes*)attributes
forNode:(UIView*)node {
[node UID_aggregateAttributes:attributes];
}
- (NSArray<id<NSObject>>*)childrenOfNode:(UIView*)node {
return [node UID_children];
}
- (UIImage*)snapshotForNode:(UIView*)node {
return [node UID_snapshot];
}
- (UIDBounds*)boundsForNode:(UIView*)node {
return [node UID_bounds];
}
@end
#endif

View File

@@ -0,0 +1,21 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDChainedDescriptor.h"
NS_ASSUME_NONNULL_BEGIN
@interface UIDUIWindowDescriptor : UIDChainedDescriptor<UIWindow*>
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDUIWindowDescriptor.h"
#import "UIView+UIDDescriptor.h"
@implementation UIDUIWindowDescriptor
- (id<NSObject>)activeChildForNode:(UIWindow*)node {
return [node UID_activeChild];
}
- (UIDBounds*)boundsForNode:(UIWindow*)node {
return [UIDBounds fromRect:node.bounds];
}
@end
#endif

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <FlipperKit/SKMacros.h>
#import <FlipperKitUIDebuggerPlugin/UIDDescriptor.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
FB_LINK_REQUIRE_CATEGORY(UIView_UIDDescriptor)
@interface UIView (UIDDescriptor)<UIDDescriptor>
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,606 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDInspectable.h"
#import "UIDMetadata.h"
#import "UIDMetadataRegister.h"
#import "UIDSnapshot.h"
#import "UIView+UIDDescriptor.h"
FB_LINKABLE(UIView_UIDDescriptor)
@implementation UIView (UIDDescriptor)
- (NSUInteger)UID_identifier {
return [self hash];
}
- (nonnull NSString*)UID_name {
return NSStringFromClass([self class]);
}
- (void)UID_aggregateAttributes:(nonnull UIDMutableAttributes*)attributes {
static UIDMetadataId UIViewAttributeId;
static UIDMetadataId FrameAttributeId;
static UIDMetadataId BoundsAttributeId;
static UIDMetadataId CenterAttributeId;
static UIDMetadataId AnchorPointAttributeId;
static UIDMetadataId SafeAreaInsetsAttributeId;
static UIDMetadataId ClipsToBoundsAttributeId;
static UIDMetadataId HiddenAttributeId;
static UIDMetadataId AlphaAttributeId;
static UIDMetadataId OpaqueAttributeId;
static UIDMetadataId ClearContextBeforeDrawingAttributeId;
static UIDMetadataId BackgroundColorAttributeId;
static UIDMetadataId TintColorAttributeId;
static UIDMetadataId TagAttributeId;
static UIDMetadataId CALayerAttributeId;
static UIDMetadataId CALayerShadowColorAttributeId;
static UIDMetadataId CALayerShadowOpacityAttributeId;
static UIDMetadataId CALayerShadowRadiusAttributeId;
static UIDMetadataId CALayerShadowOffsetAttributeId;
static UIDMetadataId CALayerBackgroundColorAttributeId;
static UIDMetadataId CALayerBorderColorAttributeId;
static UIDMetadataId CALayerBorderWidthAttributeId;
static UIDMetadataId CALayerCornerRadiusAttributeId;
static UIDMetadataId CALayerMasksToBoundsAttributeId;
static UIDMetadataId AccessibilityAttributeId;
static UIDMetadataId IsAccessibilityElementAttributeId;
static UIDMetadataId AccessibilityLabelAttributeId;
static UIDMetadataId AccessibilityIdentifierAttributeId;
static UIDMetadataId AccessibilityValueAttributeId;
static UIDMetadataId AccessibilityHintAttributeId;
static UIDMetadataId AccessibilityTraitsAttributeId;
static UIDMetadataId AccessibilityViewIsModalAttributeId;
static UIDMetadataId ShouldGroupAccessibilityChildrenAttributeId;
static UIDMetadataId AccessibilityTraitNoneAttributeId;
static UIDMetadataId AccessibilityTraitButtonAttributeId;
static UIDMetadataId AccessibilityTraitLinkAttributeId;
static UIDMetadataId AccessibilityTraitImageAttributeId;
static UIDMetadataId AccessibilityTraitSearchFieldAttributeId;
static UIDMetadataId AccessibilityTraitKeyboardKeyAttributeId;
static UIDMetadataId AccessibilityTraitStaticTextAttributeId;
static UIDMetadataId AccessibilityTraitHeaderAttributeId;
static UIDMetadataId AccessibilityTraitTabBarAttributeId;
static UIDMetadataId AccessibilityTraitSummaryElementAttributeId;
static UIDMetadataId AccessibilityTraitSelectedAttributeId;
static UIDMetadataId AccessibilityTraitNotEnabledAttributeId;
static UIDMetadataId AccessibilityTraitAdjustableAttributeId;
static UIDMetadataId AccessibilityTraitAllowsDirectInteractionAttributeId;
static UIDMetadataId AccessibilityTraitUpdatesFrequentlyAttributeId;
static UIDMetadataId AccessibilityTraitCausesPageTurnAttributeId;
static UIDMetadataId AccessibilityTraitPlaysSoundAttributeId;
static UIDMetadataId AccessibilityTraitStartsMediaSessionAttributeId;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
UIViewAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"UIView"];
FrameAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_LAYOUT
name:@"frame"
isMutable:false
definedBy:UIViewAttributeId];
BoundsAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_LAYOUT
name:@"bounds"
isMutable:false
definedBy:UIViewAttributeId];
CenterAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_LAYOUT
name:@"center"
isMutable:false
definedBy:UIViewAttributeId];
AnchorPointAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_LAYOUT
name:@"anchorPoint"
isMutable:false
definedBy:UIViewAttributeId];
SafeAreaInsetsAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_LAYOUT
name:@"safeAreaInset"
isMutable:false
definedBy:UIViewAttributeId];
ClipsToBoundsAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_LAYOUT
name:@"clipsToBounds"
isMutable:false
definedBy:UIViewAttributeId];
HiddenAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"hidden"
isMutable:false
definedBy:UIViewAttributeId];
AlphaAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"alpha"
isMutable:false
definedBy:UIViewAttributeId];
OpaqueAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"opaque"
isMutable:false
definedBy:UIViewAttributeId];
ClearContextBeforeDrawingAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"clearContextBeforeDrawing"
isMutable:false
definedBy:UIViewAttributeId];
BackgroundColorAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"backgroundColor"
isMutable:false
definedBy:UIViewAttributeId];
TintColorAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"tintColor"
isMutable:false
definedBy:UIViewAttributeId];
TagAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"tag"
isMutable:false
definedBy:UIViewAttributeId];
CALayerAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"CALayer"];
CALayerShadowColorAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"shadowColor"
isMutable:false
definedBy:CALayerAttributeId];
CALayerShadowOpacityAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"shadowOpacity"
isMutable:false
definedBy:CALayerAttributeId];
CALayerShadowRadiusAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"shadowRadius"
isMutable:false
definedBy:CALayerAttributeId];
CALayerShadowOffsetAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"shadowOffset"
isMutable:false
definedBy:CALayerAttributeId];
CALayerBackgroundColorAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"shadowBackgroundColor"
isMutable:false
definedBy:CALayerAttributeId];
CALayerBorderColorAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"borderColor"
isMutable:false
definedBy:CALayerAttributeId];
CALayerBorderWidthAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"borderWidth"
isMutable:false
definedBy:CALayerAttributeId];
CALayerCornerRadiusAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"cornerRadius"
isMutable:false
definedBy:CALayerAttributeId];
CALayerMasksToBoundsAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"masksToBounds"
isMutable:false
definedBy:CALayerAttributeId];
AccessibilityAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"Accessibility"];
IsAccessibilityElementAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"isAccessibilityElement"
isMutable:false
definedBy:AccessibilityAttributeId];
AccessibilityLabelAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"accessibilityLabel"
isMutable:false
definedBy:AccessibilityAttributeId];
AccessibilityIdentifierAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"accessibilityIdentifier"
isMutable:false
definedBy:AccessibilityAttributeId];
AccessibilityValueAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"accessibilityValue"
isMutable:false
definedBy:AccessibilityAttributeId];
AccessibilityHintAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"accessibilityHint"
isMutable:false
definedBy:AccessibilityAttributeId];
AccessibilityTraitsAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"accessibilityTraits"
isMutable:false
definedBy:AccessibilityAttributeId];
AccessibilityViewIsModalAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"accessibilityViewIsModal"
isMutable:false
definedBy:AccessibilityAttributeId];
ShouldGroupAccessibilityChildrenAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"shouldGroupAccessibilityChildren"
isMutable:false
definedBy:AccessibilityAttributeId];
AccessibilityTraitNoneAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"none"
isMutable:false
definedBy:AccessibilityTraitsAttributeId];
AccessibilityTraitButtonAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"button"
isMutable:false
definedBy:AccessibilityTraitsAttributeId];
AccessibilityTraitLinkAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"link"
isMutable:false
definedBy:AccessibilityTraitsAttributeId];
AccessibilityTraitImageAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"image"
isMutable:false
definedBy:AccessibilityTraitsAttributeId];
AccessibilityTraitSearchFieldAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"searchField"
isMutable:false
definedBy:AccessibilityTraitsAttributeId];
AccessibilityTraitKeyboardKeyAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"keyboardKey"
isMutable:false
definedBy:AccessibilityTraitsAttributeId];
AccessibilityTraitStaticTextAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"staticText"
isMutable:false
definedBy:AccessibilityTraitsAttributeId];
AccessibilityTraitHeaderAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"header"
isMutable:false
definedBy:AccessibilityTraitsAttributeId];
AccessibilityTraitTabBarAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"tabBar"
isMutable:false
definedBy:AccessibilityTraitsAttributeId];
AccessibilityTraitSummaryElementAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"summaryElement"
isMutable:false
definedBy:AccessibilityTraitsAttributeId];
AccessibilityTraitSelectedAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"selected"
isMutable:false
definedBy:AccessibilityTraitsAttributeId];
AccessibilityTraitNotEnabledAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"notEnabled"
isMutable:false
definedBy:AccessibilityTraitsAttributeId];
AccessibilityTraitAdjustableAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"adjustable"
isMutable:false
definedBy:AccessibilityTraitsAttributeId];
AccessibilityTraitAllowsDirectInteractionAttributeId =
[[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"directInteraction"
isMutable:false
definedBy:AccessibilityTraitsAttributeId];
AccessibilityTraitUpdatesFrequentlyAttributeId =
[[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"updatedFrequently"
isMutable:false
definedBy:AccessibilityTraitsAttributeId];
AccessibilityTraitCausesPageTurnAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"causesPageTurn"
isMutable:false
definedBy:AccessibilityTraitsAttributeId];
AccessibilityTraitPlaysSoundAttributeId = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"playsSound"
isMutable:false
definedBy:AccessibilityTraitsAttributeId];
AccessibilityTraitStartsMediaSessionAttributeId =
[[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"startsMediaSession"
isMutable:false
definedBy:AccessibilityTraitsAttributeId];
});
NSMutableDictionary* viewAttributes = [NSMutableDictionary new];
[viewAttributes setObject:[UIDInspectableBounds fromRect:self.frame]
forKey:FrameAttributeId];
[viewAttributes setObject:[UIDInspectableBounds fromRect:self.bounds]
forKey:BoundsAttributeId];
[viewAttributes setObject:[UIDInspectableCoordinate fromPoint:self.center]
forKey:CenterAttributeId];
if (@available(iOS 16.0, *)) {
[viewAttributes
setObject:[UIDInspectableCoordinate fromPoint:self.anchorPoint]
forKey:AnchorPointAttributeId];
}
[viewAttributes
setObject:[UIDInspectableEdgeInsets fromUIEdgeInsets:self.safeAreaInsets]
forKey:SafeAreaInsetsAttributeId];
[viewAttributes
setObject:[UIDInspectableBoolean fromBoolean:self.clipsToBounds]
forKey:ClipsToBoundsAttributeId];
[viewAttributes setObject:[UIDInspectableBoolean fromBoolean:self.isHidden]
forKey:HiddenAttributeId];
[viewAttributes setObject:[UIDInspectableNumber fromCGFloat:self.alpha]
forKey:AlphaAttributeId];
[viewAttributes setObject:[UIDInspectableBoolean fromBoolean:self.opaque]
forKey:OpaqueAttributeId];
[viewAttributes setObject:[UIDInspectableBoolean
fromBoolean:self.clearsContextBeforeDrawing]
forKey:ClearContextBeforeDrawingAttributeId];
[viewAttributes setObject:[UIDInspectableColor fromColor:self.backgroundColor]
forKey:BackgroundColorAttributeId];
[viewAttributes setObject:[UIDInspectableColor fromColor:self.tintColor]
forKey:TintColorAttributeId];
[viewAttributes setObject:[UIDInspectableNumber fromNumber:@(self.tag)]
forKey:TagAttributeId];
[attributes setObject:[UIDInspectableObject fromFields:viewAttributes]
forKey:UIViewAttributeId];
NSMutableDictionary* layerAttributes = [NSMutableDictionary new];
[layerAttributes
setObject:[UIDInspectableColor
fromColor:[UIColor colorWithCGColor:self.layer.shadowColor]]
forKey:CALayerShadowColorAttributeId];
[layerAttributes
setObject:[UIDInspectableNumber fromCGFloat:self.layer.shadowOpacity]
forKey:CALayerShadowOpacityAttributeId];
[layerAttributes
setObject:[UIDInspectableNumber fromCGFloat:self.layer.shadowRadius]
forKey:CALayerShadowRadiusAttributeId];
[layerAttributes
setObject:[UIDInspectableSize fromSize:self.layer.shadowOffset]
forKey:CALayerShadowOffsetAttributeId];
[layerAttributes
setObject:[UIDInspectableColor
fromColor:[UIColor
colorWithCGColor:self.layer.backgroundColor]]
forKey:CALayerBackgroundColorAttributeId];
[layerAttributes
setObject:[UIDInspectableColor
fromColor:[UIColor colorWithCGColor:self.layer.borderColor]]
forKey:CALayerBorderColorAttributeId];
[layerAttributes
setObject:[UIDInspectableNumber fromCGFloat:self.layer.borderWidth]
forKey:CALayerBorderWidthAttributeId];
[layerAttributes
setObject:[UIDInspectableNumber fromCGFloat:self.layer.cornerRadius]
forKey:CALayerCornerRadiusAttributeId];
[layerAttributes
setObject:[UIDInspectableBoolean fromBoolean:self.layer.masksToBounds]
forKey:CALayerMasksToBoundsAttributeId];
[attributes setObject:[UIDInspectableObject fromFields:layerAttributes]
forKey:CALayerAttributeId];
NSMutableDictionary* accessibilityAttributes = [NSMutableDictionary new];
[accessibilityAttributes
setObject:[UIDInspectableBoolean fromBoolean:self.isAccessibilityElement]
forKey:IsAccessibilityElementAttributeId];
[accessibilityAttributes
setObject:[UIDInspectableText fromText:self.accessibilityLabel]
forKey:AccessibilityLabelAttributeId];
[accessibilityAttributes
setObject:[UIDInspectableText fromText:self.accessibilityIdentifier]
forKey:AccessibilityIdentifierAttributeId];
[accessibilityAttributes
setObject:[UIDInspectableText fromText:self.accessibilityValue]
forKey:AccessibilityValueAttributeId];
[accessibilityAttributes
setObject:[UIDInspectableText fromText:self.accessibilityHint]
forKey:AccessibilityHintAttributeId];
[accessibilityAttributes
setObject:[UIDInspectableBoolean
fromBoolean:self.accessibilityViewIsModal]
forKey:AccessibilityViewIsModalAttributeId];
[accessibilityAttributes
setObject:[UIDInspectableBoolean
fromBoolean:self.shouldGroupAccessibilityChildren]
forKey:ShouldGroupAccessibilityChildrenAttributeId];
NSMutableDictionary* accessibilityTraitsAttributes =
[NSMutableDictionary new];
[accessibilityTraitsAttributes
setObject:[UIDInspectableBoolean fromBoolean:(self.accessibilityTraits &
UIAccessibilityTraitNone)]
forKey:AccessibilityTraitNoneAttributeId];
[accessibilityTraitsAttributes
setObject:[UIDInspectableBoolean fromBoolean:(self.accessibilityTraits &
UIAccessibilityTraitButton)]
forKey:AccessibilityTraitButtonAttributeId];
[accessibilityTraitsAttributes
setObject:[UIDInspectableBoolean fromBoolean:(self.accessibilityTraits &
UIAccessibilityTraitLink)]
forKey:AccessibilityTraitLinkAttributeId];
[accessibilityTraitsAttributes
setObject:[UIDInspectableBoolean fromBoolean:(self.accessibilityTraits &
UIAccessibilityTraitImage)]
forKey:AccessibilityTraitImageAttributeId];
[accessibilityTraitsAttributes
setObject:[UIDInspectableBoolean
fromBoolean:(self.accessibilityTraits &
UIAccessibilityTraitSearchField)]
forKey:AccessibilityTraitSearchFieldAttributeId];
[accessibilityTraitsAttributes
setObject:[UIDInspectableBoolean
fromBoolean:(self.accessibilityTraits &
UIAccessibilityTraitKeyboardKey)]
forKey:AccessibilityTraitKeyboardKeyAttributeId];
[accessibilityTraitsAttributes
setObject:[UIDInspectableBoolean
fromBoolean:(self.accessibilityTraits &
UIAccessibilityTraitStaticText)]
forKey:AccessibilityTraitStaticTextAttributeId];
[accessibilityTraitsAttributes
setObject:[UIDInspectableBoolean fromBoolean:(self.accessibilityTraits &
UIAccessibilityTraitHeader)]
forKey:AccessibilityTraitHeaderAttributeId];
[accessibilityTraitsAttributes
setObject:[UIDInspectableBoolean fromBoolean:(self.accessibilityTraits &
UIAccessibilityTraitTabBar)]
forKey:AccessibilityTraitTabBarAttributeId];
[accessibilityTraitsAttributes
setObject:[UIDInspectableBoolean
fromBoolean:(self.accessibilityTraits &
UIAccessibilityTraitSummaryElement)]
forKey:AccessibilityTraitSummaryElementAttributeId];
[accessibilityTraitsAttributes
setObject:[UIDInspectableBoolean
fromBoolean:(self.accessibilityTraits &
UIAccessibilityTraitSelected)]
forKey:AccessibilityTraitSelectedAttributeId];
[accessibilityTraitsAttributes
setObject:[UIDInspectableBoolean
fromBoolean:(self.accessibilityTraits &
UIAccessibilityTraitNotEnabled)]
forKey:AccessibilityTraitNotEnabledAttributeId];
[accessibilityTraitsAttributes
setObject:[UIDInspectableBoolean
fromBoolean:(self.accessibilityTraits &
UIAccessibilityTraitAdjustable)]
forKey:AccessibilityTraitAdjustableAttributeId];
[accessibilityTraitsAttributes
setObject:[UIDInspectableBoolean
fromBoolean:(self.accessibilityTraits &
UIAccessibilityTraitAllowsDirectInteraction)]
forKey:AccessibilityTraitAllowsDirectInteractionAttributeId];
[accessibilityTraitsAttributes
setObject:[UIDInspectableBoolean
fromBoolean:(self.accessibilityTraits &
UIAccessibilityTraitUpdatesFrequently)]
forKey:AccessibilityTraitUpdatesFrequentlyAttributeId];
[accessibilityTraitsAttributes
setObject:[UIDInspectableBoolean
fromBoolean:(self.accessibilityTraits &
UIAccessibilityTraitCausesPageTurn)]
forKey:AccessibilityTraitCausesPageTurnAttributeId];
[accessibilityTraitsAttributes
setObject:[UIDInspectableBoolean
fromBoolean:(self.accessibilityTraits &
UIAccessibilityTraitPlaysSound)]
forKey:AccessibilityTraitPlaysSoundAttributeId];
[accessibilityTraitsAttributes
setObject:[UIDInspectableBoolean
fromBoolean:(self.accessibilityTraits &
UIAccessibilityTraitStartsMediaSession)]
forKey:AccessibilityTraitStartsMediaSessionAttributeId];
[accessibilityAttributes
setObject:[UIDInspectableObject fromFields:accessibilityTraitsAttributes]
forKey:AccessibilityTraitsAttributeId];
[attributes
setObject:[UIDInspectableObject fromFields:accessibilityAttributes]
forKey:AccessibilityAttributeId];
}
- (NSArray<id<NSObject>>*)UID_children {
NSMutableArray* children = [NSMutableArray new];
// Use UIViewControllers for children which responds to a different
// view controller than their parent.
for (UIView* child in self.subviews) {
BOOL isController =
[child.nextResponder isKindOfClass:[UIViewController class]];
if (!child.isHidden) {
if (isController && child.nextResponder != self.nextResponder) {
[children addObject:child.nextResponder];
} else {
[children addObject:child];
}
}
}
return children;
}
/**
In the context of UIView, the active child is defined as the last view in
the subviews collection. If said item's next responder is a UIViewController,
then return this instead.
*/
- (id<NSObject>)UID_activeChild {
if (self.subviews && self.subviews.count > 0) {
UIView* activeChild = [self.subviews lastObject];
BOOL isController =
[activeChild.nextResponder isKindOfClass:[UIViewController class]];
if (!activeChild.isHidden) {
if (isController && activeChild.nextResponder != self.nextResponder) {
return activeChild.nextResponder;
}
return activeChild;
}
}
return nil;
}
- (UIImage*)UID_snapshot {
return UIDViewSnapshot(self);
}
- (UIDBounds*)UID_bounds {
if ([self.superview isKindOfClass:[UIScrollView class]]) {
UIScrollView* parent = (UIScrollView*)self.superview;
CGFloat x = self.frame.origin.x - parent.contentOffset.x;
CGFloat y = self.frame.origin.y - parent.contentOffset.y;
CGFloat width = self.frame.size.width;
CGFloat height = self.frame.size.height;
return [UIDBounds fromRect:CGRectMake(x, y, width, height)];
}
return [UIDBounds fromRect:self.frame];
}
@end
#endif

View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class UIDFrameworkEventMetadata;
@interface UIDInitEvent : NSObject
@property(nonatomic) NSUInteger rootId;
@property(nonatomic, strong)
NSArray<UIDFrameworkEventMetadata*>* frameworkEventMetadata;
+ (NSString*)name;
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,20 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDInitEvent.h"
@implementation UIDInitEvent
+ (NSString*)name {
return @"init";
}
@end
#endif

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class UIDMetadata;
@interface UIDMetadataUpdateEvent : NSObject
@property(nonatomic, strong)
NSDictionary<NSNumber*, UIDMetadata*>* attributeMetadata;
+ (NSString*)name;
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,20 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDMetadataUpdateEvent.h"
@implementation UIDMetadataUpdateEvent
+ (NSString*)name {
return @"metadataUpdate";
}
@end
#endif

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIDPerfStatsEvent : NSObject
@property(nonatomic) double txId;
@property(nonatomic, strong) NSString* observerType;
@property(nonatomic) NSUInteger nodesCount;
@property(nonatomic) long start;
@property(nonatomic) long traversalMS;
@property(nonatomic) long snapshotMS;
@property(nonatomic) long queuingMS;
@property(nonatomic) long deferredComputationMS;
@property(nonatomic) long serializationMS;
@property(nonatomic) long socketMS;
@property(nonatomic) long frameworkEventsMS;
@property(nonatomic) long payloadSize;
@property(nonatomic) NSUInteger eventsCount;
@property(nonatomic) NSDictionary<NSString*, NSNumber*>* dynamicMeasures;
+ (NSString*)name;
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,20 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDPerfStatsEvent.h"
@implementation UIDPerfStatsEvent
+ (NSString*)name {
return @"performanceStats";
}
@end
#endif

View File

@@ -0,0 +1,31 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDFrameworkEvent.h"
#import "UIDNode.h"
NS_ASSUME_NONNULL_BEGIN
@interface UIDSubtreeUpdateEvent : NSObject
@property(nonatomic) double txId;
@property(nonatomic, strong) NSString* observerType;
@property(nonatomic) NSUInteger rootId;
@property(nonatomic, strong) NSArray<UIDNode*>* nodes;
@property(nonatomic, strong) UIImage* snapshot;
@property(nonatomic, strong) NSArray<UIDFrameworkEvent*>* frameworkEvents;
+ (NSString*)name;
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,20 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDSubtreeUpdateEvent.h"
@implementation UIDSubtreeUpdateEvent
+ (NSString*)name {
return @"subtreeUpdate";
}
@end
#endif

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <FlipperKit/FlipperPlugin.h>
#import <Foundation/Foundation.h>
@class FlipperClient;
@interface FlipperKitUIDebuggerPlugin : NSObject<FlipperPlugin>
@end
FB_EXTERN_C_BEGIN
void FlipperKitUIDebuggerAddPlugin(FlipperClient*);
FB_EXTERN_C_END
#endif

View File

@@ -0,0 +1,85 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "FlipperKitUIDebuggerPlugin.h"
#import <UIKit/UIKit.h>
#import <FlipperKit/FlipperClient.h>
#import <FlipperKit/FlipperConnection.h>
#import <FlipperKit/FlipperResponder.h>
#import "Core/UIDContext.h"
#import "PluginSockets.h"
#import "Plugins.h"
#import "Descriptors/UIDDescriptorRegister.h"
#import "Observer/UIDTreeObserverFactory.h"
#import "Observer/UIDTreeObserverManager.h"
@implementation FlipperKitUIDebuggerPlugin {
UIDContext* _context;
}
- (instancetype)initWithContext:(UIDContext*)context {
if (self = [super init]) {
self->_context = context;
}
return self;
}
- (instancetype)init {
UIDContext* context = [[UIDContext alloc]
initWithApplication:[UIApplication sharedApplication]
descriptorRegister:[UIDDescriptorRegister defaultRegister]
observerFactory:[UIDTreeObserverFactory shared]];
return [self initWithContext:context];
}
- (NSString*)identifier {
return @"ui-debugger";
}
- (void)didConnect:(id<FlipperConnection>)connection {
if (!_context.application) {
_context.application = [UIApplication sharedApplication];
}
_context.connection = connection;
[[UIDTreeObserverManager shared] startWithContext:_context];
}
- (void)didDisconnect {
_context.connection = nil;
[[UIDTreeObserverManager shared] stop];
}
@end
void FlipperKitUIDebuggerAddPlugin(FlipperClient* client) {
UIDContext* context = [[UIDContext alloc]
initWithApplication:[UIApplication sharedApplication]
descriptorRegister:[UIDDescriptorRegister defaultRegister]
observerFactory:[UIDTreeObserverFactory shared]];
FlipperKitUIDebuggerPlugin* plugin =
[[FlipperKitUIDebuggerPlugin alloc] initWithContext:context];
for (const auto& p : FlipperUIDebuggerDescriptorRegisterSocket_Plugins()) {
FlipperUIDebuggerDescriptorRegisterSocket_InvokeConfigure(p, context);
}
[client addPlugin:plugin];
}
void FlipperKitUIDebuggerPluginInit(FlipperClient* client) {
FlipperKitUIDebuggerAddPlugin(client);
}
#endif

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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>
NS_ASSUME_NONNULL_BEGIN
@interface UIDBounds : NSObject
@property(nonatomic) NSInteger x;
@property(nonatomic) NSInteger y;
@property(nonatomic) NSInteger width;
@property(nonatomic) NSInteger height;
- (instancetype)initWithX:(NSInteger)x
y:(NSInteger)y
width:(NSInteger)width
height:(NSInteger)height;
+ (instancetype)fromRect:(CGRect)rect;
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDBounds.h"
@implementation UIDBounds
- (instancetype)initWithX:(NSInteger)x
y:(NSInteger)y
width:(NSInteger)width
height:(NSInteger)height {
self = [super init];
if (self) {
self.x = x;
self.y = y;
self.width = width;
self.height = height;
}
return self;
}
+ (instancetype)fromRect:(CGRect)rect {
return [[UIDBounds alloc] initWithX:rect.origin.x
y:rect.origin.y
width:rect.size.width
height:rect.size.height];
}
@end
#endif

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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>
NS_ASSUME_NONNULL_BEGIN
@interface UIDEdgeInsets : NSObject
@property(nonatomic) CGFloat top;
@property(nonatomic) CGFloat right;
@property(nonatomic) CGFloat bottom;
@property(nonatomic) CGFloat left;
- (instancetype)initWithTop:(CGFloat)top
right:(CGFloat)right
bottom:(CGFloat)bottom
left:(CGFloat)left;
+ (instancetype)fromUIEdgeInsets:(UIEdgeInsets)edgeInsets;
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDEdgeInsets.h"
@implementation UIDEdgeInsets
- (instancetype)initWithTop:(CGFloat)top
right:(CGFloat)right
bottom:(CGFloat)bottom
left:(CGFloat)left {
self = [super init];
if (self) {
_top = top;
_right = right;
_bottom = bottom;
_left = left;
}
return self;
}
+ (instancetype)fromUIEdgeInsets:(UIEdgeInsets)edgeInsets {
return [[UIDEdgeInsets alloc] initWithTop:edgeInsets.top
right:edgeInsets.right
bottom:edgeInsets.bottom
left:edgeInsets.left];
}
@end
#endif

View File

@@ -0,0 +1,29 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
typedef NSDictionary<NSString*, id>* UIDEventPayload;
typedef NSArray<NSString*>* UIDStacktrace;
@interface UIDFrameworkEvent : NSObject
@property(nonatomic) NSUInteger nodeIdentifier;
@property(nonatomic, strong) NSString* type;
@property(nonatomic, strong) NSDate* timestamp;
@property(nonatomic, strong) UIDEventPayload payload;
@property(nonatomic, strong) UIDStacktrace stacktrace;
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,16 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDFrameworkEvent.h"
@implementation UIDFrameworkEvent
@end
#endif

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIDFrameworkEventMetadata : NSObject
@property(nonatomic, strong) NSString* type;
@property(nonatomic, strong) NSString* documentation;
+ (instancetype)newWithType:(NSString*)type
documentation:(NSString*)documentation;
+ (instancetype)new NS_UNAVAILABLE;
- (instancetype)init NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDFrameworkEventMetadata.h"
@implementation UIDFrameworkEventMetadata
- (instancetype)initWithType:(NSString*)type
documentation:(NSString*)documentation {
if (self = [super init]) {
self->_type = type;
self->_documentation = documentation;
}
return self;
}
+ (instancetype)newWithType:(NSString*)type
documentation:(NSString*)documentation {
return [[self alloc] initWithType:type documentation:documentation];
}
@end
#endif

View File

@@ -0,0 +1,175 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDFoundation.h"
NS_ASSUME_NONNULL_BEGIN
@interface UIDInspectable : NSObject
@end
/**
Lazy inspectables can be used to defer materialisation
of the inspectable until a later stage, like for example,
during serialisation.
*/
@interface UIDLazyInspectable : UIDInspectable
- (UIDInspectable*)value;
+ (instancetype)from:(UIDInspectable* (^)(void))loader;
@end
@interface UIDInspectableValue : UIDInspectable
+ (instancetype)createWithText:(NSString*)text;
+ (instancetype)createWithBoolean:(bool)boolean;
+ (instancetype)createWithNumber:(NSNumber*)number;
@end
@interface UIDInspectableObject : UIDInspectable
@property(nonatomic, strong, readonly)
NSDictionary<NSNumber*, UIDInspectable*>* fields;
- (instancetype)initWithFields:
(NSDictionary<NSNumber*, UIDInspectable*>*)fields;
+ (instancetype)fromFields:(NSDictionary<NSNumber*, UIDInspectable*>*)fields;
@end
@interface UIDInspectableArray : UIDInspectable
@property(nonatomic, strong, readonly) NSArray<UIDInspectable*>* items;
- (instancetype)initWithItems:(NSArray<UIDInspectable*>*)items;
+ (instancetype)fromItems:(NSArray<UIDInspectable*>*)items;
@end
@interface UIDInspectableText : UIDInspectableValue
@property(nonatomic, strong, readonly) NSString* value;
- (instancetype)initWithValue:(NSString*)value;
+ (instancetype)fromText:(NSString*)value;
@end
@interface UIDInspectableBoolean : UIDInspectableValue
@property(nonatomic, readonly) bool value;
- (instancetype)initWithValue:(bool)value;
+ (instancetype)fromBoolean:(bool)value;
@end
@interface UIDInspectableNumber : UIDInspectableValue
@property(nonatomic, strong, readonly) NSNumber* value;
- (instancetype)initWithValue:(NSNumber*)value;
+ (instancetype)fromNumber:(NSNumber*)value;
+ (instancetype)fromCGFloat:(CGFloat)value;
@end
@class UIDBounds;
@interface UIDInspectableBounds : UIDInspectableValue
@property(nonatomic, strong, readonly) UIDBounds* value;
- (instancetype)initWithValue:(UIDBounds*)value;
+ (instancetype)fromBounds:(UIDBounds*)value;
+ (instancetype)fromRect:(CGRect)rect;
@end
@interface UIDInspectableCoordinate : UIDInspectableValue
@property(nonatomic, readonly) CGPoint value;
- (instancetype)initWithValue:(CGPoint)value;
+ (instancetype)fromPoint:(CGPoint)value;
@end
@interface UIDInspectableSize : UIDInspectableValue
@property(nonatomic, readonly) CGSize value;
- (instancetype)initWithValue:(CGSize)value;
+ (instancetype)fromSize:(CGSize)value;
@end
@interface UIDInspectableUnknown : UIDInspectableValue
@property(nonatomic, readonly) NSString* value;
- (instancetype)initWithValue:(NSString*)value;
+ (instancetype)unknown;
+ (instancetype)undefined;
+ (instancetype)null;
@end
@class UIDEdgeInsets;
@interface UIDInspectableEdgeInsets : UIDInspectableValue
@property(nonatomic, readonly) UIDEdgeInsets* value;
- (instancetype)initWithValue:(UIDEdgeInsets*)value;
+ (instancetype)fromEdgeInsets:(UIDEdgeInsets*)value;
+ (instancetype)fromUIEdgeInsets:(UIEdgeInsets)value;
@end
@interface UIDInspectableColor : UIDInspectableValue
@property(nonatomic, strong, readonly) UIColor* value;
- (instancetype)initWithValue:(UIColor*)value;
+ (instancetype)fromColor:(UIColor*)value;
@end
@interface UIDInspectableEnum : UIDInspectableValue
@property(nonatomic, readonly) NSString* value;
- (instancetype)initWithValue:(NSString*)value;
+ (instancetype)from:(NSString*)value;
@end
typedef NSDictionary<NSNumber*, UIDInspectable*> UIDAttributes;
typedef NSMutableDictionary<NSNumber*, UIDInspectable*> UIDMutableAttributes;
typedef NSDictionary<NSString*, NSString*> UIDInlineAttributes;
typedef NSMutableDictionary<NSString*, NSString*> UIDMutableInlineAttributes;
typedef NSDictionary<NSString*, id<UIDFoundation>> UIDGenericAttributes;
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,275 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDInspectable.h"
#import "UIDBounds.h"
#import "UIDEdgeInsets.h"
@implementation UIDInspectable
@end
@interface UIDLazyInspectable () {
UIDInspectable* _value;
UIDInspectable* (^_loader)(void);
}
@end
@implementation UIDLazyInspectable
- (instancetype)initWithLoader:(UIDInspectable* (^)(void))loader {
if (self = [super init]) {
self->_value = nil;
self->_loader = loader;
}
return self;
}
- (UIDInspectable*)value {
if (!_value && _loader) {
_value = _loader();
}
return _value;
}
+ (instancetype)from:(UIDInspectable* (^)(void))loader {
return [[self alloc] initWithLoader:loader];
}
@end
@implementation UIDInspectableObject
- (instancetype)initWithFields:
(NSDictionary<NSNumber*, UIDInspectable*>*)fields {
self = [super init];
if (self) {
_fields = fields;
}
return self;
}
+ (instancetype)fromFields:(NSDictionary<NSNumber*, UIDInspectable*>*)fields {
return [[UIDInspectableObject alloc] initWithFields:fields];
}
@end
@implementation UIDInspectableArray
- (instancetype)initWithItems:(NSArray<UIDInspectable*>*)items {
self = [super init];
if (self) {
_items = items;
}
return self;
}
+ (instancetype)fromItems:(NSArray<UIDInspectable*>*)items {
return [[UIDInspectableArray alloc] initWithItems:items];
}
@end
@implementation UIDInspectableValue
+ (instancetype)createWithText:(NSString*)text {
return [[UIDInspectableText alloc] initWithValue:text];
}
+ (instancetype)createWithBoolean:(bool)boolean {
return [[UIDInspectableBoolean alloc] initWithValue:boolean];
}
+ (instancetype)createWithNumber:(NSNumber*)number {
return [[UIDInspectableNumber alloc] initWithValue:number];
}
@end
@implementation UIDInspectableText
- (instancetype)initWithValue:(NSString*)value {
self = [super init];
if (self) {
_value = value;
}
return self;
}
+ (instancetype)fromText:(NSString*)value {
return [[UIDInspectableText alloc] initWithValue:value];
}
@end
@implementation UIDInspectableBoolean
- (instancetype)initWithValue:(bool)value {
self = [super init];
if (self) {
_value = value;
}
return self;
}
+ (instancetype)fromBoolean:(bool)value {
return [[UIDInspectableBoolean alloc] initWithValue:value];
}
@end
@implementation UIDInspectableNumber
- (instancetype)initWithValue:(NSNumber*)value {
self = [super init];
if (self) {
_value = value;
}
return self;
}
+ (instancetype)fromNumber:(NSNumber*)value {
return [[UIDInspectableNumber alloc] initWithValue:value];
}
+ (instancetype)fromCGFloat:(CGFloat)value {
return [self fromNumber:[NSNumber numberWithFloat:value]];
}
@end
@implementation UIDInspectableBounds
- (instancetype)initWithValue:(UIDBounds*)value {
self = [super init];
if (self) {
_value = value;
}
return self;
}
+ (instancetype)fromBounds:(UIDBounds*)bounds {
return [[UIDInspectableBounds alloc] initWithValue:bounds];
}
+ (instancetype)fromRect:(CGRect)rect {
return [self fromBounds:[UIDBounds fromRect:rect]];
}
@end
@implementation UIDInspectableCoordinate
- (instancetype)initWithValue:(CGPoint)value {
self = [super init];
if (self) {
_value = value;
}
return self;
}
+ (instancetype)fromPoint:(CGPoint)value {
return [[UIDInspectableCoordinate alloc] initWithValue:value];
}
@end
@implementation UIDInspectableSize
- (instancetype)initWithValue:(CGSize)value {
self = [super init];
if (self) {
_value = value;
}
return self;
}
+ (instancetype)fromSize:(CGSize)value {
return [[UIDInspectableSize alloc] initWithValue:value];
}
@end
@implementation UIDInspectableEdgeInsets
- (instancetype)initWithValue:(UIDEdgeInsets*)value {
self = [super init];
if (self) {
_value = value;
}
return self;
}
+ (instancetype)fromEdgeInsets:(UIDEdgeInsets*)value {
return [[UIDInspectableEdgeInsets alloc] initWithValue:value];
}
+ (instancetype)fromUIEdgeInsets:(UIEdgeInsets)value {
return [self fromEdgeInsets:[UIDEdgeInsets fromUIEdgeInsets:value]];
}
@end
@implementation UIDInspectableColor
- (instancetype)initWithValue:(UIColor*)value {
self = [super init];
if (self) {
_value = value;
}
return self;
}
+ (instancetype)fromColor:(UIColor*)value {
return [[UIDInspectableColor alloc] initWithValue:value];
}
@end
@implementation UIDInspectableUnknown
- (instancetype)initWithValue:(NSString*)value {
self = [super init];
if (self) {
_value = value;
}
return self;
}
+ (instancetype)unknown {
return [[UIDInspectableUnknown alloc] initWithValue:@"unknown"];
}
+ (instancetype)undefined {
return [[UIDInspectableUnknown alloc] initWithValue:@"undefined"];
}
+ (instancetype)null {
return [[UIDInspectableUnknown alloc] initWithValue:@"null"];
}
@end
@implementation UIDInspectableEnum
- (instancetype)initWithValue:(NSString*)value {
self = [super init];
if (self) {
_value = value;
}
return self;
}
+ (instancetype)from:(NSString*)value {
return [[UIDInspectableEnum alloc] initWithValue:value ?: @"UNKNOWN"];
}
@end
#endif

View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
typedef NSNumber* UIDMetadataId;
@class UIDInspectableValue;
/**
Represent metadata associated for an attribute. Metadata identifier is a
unique identifier used by attributes to refer to its metadata. Type refers to
attribute semantics. It can represent: identity, attributes, layout,
documentation, or a custom type.
*/
@interface UIDMetadata : NSObject
@property(nonatomic, readonly) UIDMetadataId identifier;
@property(nonatomic, strong, readonly) NSString* type;
@property(nonatomic, readonly) UIDMetadataId parent;
@property(nonatomic, strong, readonly) NSString* name;
@property(nonatomic, readonly) bool isMutable;
@property(nonatomic, strong, readonly)
NSSet<UIDInspectableValue*>* possibleValues;
@property(nonatomic, strong, readonly) NSSet<NSString*>* tags;
- (instancetype)initWithIdentifier:(UIDMetadataId)identifier
type:(NSString*)type
name:(NSString*)name;
- (instancetype)initWithIdentifier:(UIDMetadataId)identifier
type:(NSString*)type
name:(NSString*)name
isMutable:(bool)isMutable
parent:(UIDMetadataId)parent;
- (instancetype)initWithIdentifier:(UIDMetadataId)identifier
type:(NSString*)type
name:(NSString*)name
isMutable:(bool)isMutable
parent:(UIDMetadataId)parent
possibleValues:(NSSet<UIDInspectableValue*>*)possibleValues
tags:(NSSet<NSString*>*)tags;
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDMetadata.h"
#import "UIDInspectable.h"
@implementation UIDMetadata
- (instancetype)initWithIdentifier:(UIDMetadataId)identifier
type:(NSString*)type
name:(NSString*)name {
return [self initWithIdentifier:identifier
type:type
name:name
isMutable:false
parent:@0
possibleValues:[NSSet set]
tags:[NSSet set]];
}
- (instancetype)initWithIdentifier:(UIDMetadataId)identifier
type:(NSString*)type
name:(NSString*)name
isMutable:(bool)isMutable
parent:(UIDMetadataId)parent {
return [self initWithIdentifier:identifier
type:type
name:name
isMutable:isMutable
parent:parent
possibleValues:[NSSet set]
tags:[NSSet set]];
}
- (instancetype)initWithIdentifier:(UIDMetadataId)identifier
type:(NSString*)type
name:(NSString*)name
isMutable:(bool)isMutable
parent:(UIDMetadataId)parent
possibleValues:(NSSet<UIDInspectableValue*>*)possibleValues
tags:(NSSet<NSString*>*)tags {
self = [super init];
if (self) {
_identifier = identifier;
_type = type;
_name = name;
_isMutable = isMutable;
_parent = parent;
_possibleValues = possibleValues;
_tags = tags;
}
return self;
}
@end
#endif

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <Foundation/Foundation.h>
#import "UIDBounds.h"
#import "UIDInspectable.h"
#import "UIDMetadata.h"
NS_ASSUME_NONNULL_BEGIN
@interface UIDNode : NSObject
@property(nonatomic) NSUInteger identifier;
@property(nonatomic, strong) NSString* qualifiedName;
@property(nonatomic, strong) NSString* name;
@property(nonatomic, strong) UIDBounds* bounds;
@property(nonatomic, strong) NSSet<NSString*>* tags;
@property(nonatomic, strong) UIDAttributes* attributes;
@property(nonatomic, strong) UIDInlineAttributes* inlineAttributes;
@property(nonatomic, strong) UIDGenericAttributes* hiddenAttributes;
@property(nonatomic, nullable) NSNumber* parent;
@property(nonatomic, strong) NSArray<NSNumber*>* children;
@property(nonatomic) NSNumber* activeChild;
- (instancetype)initWithIdentifier:(NSUInteger)identifier
qualifiedName:(NSString*)qualifiedName
name:(NSString*)name
bounds:(UIDBounds*)bounds
tags:(NSSet<NSString*>*)tags;
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,36 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDNode.h"
@implementation UIDNode
- (instancetype)initWithIdentifier:(NSUInteger)identifier
qualifiedName:(NSString*)qualifiedName
name:(NSString*)name
bounds:(UIDBounds*)bounds
tags:(NSSet<NSString*>*)tags {
self = [super init];
if (self) {
self.identifier = identifier;
self.qualifiedName = qualifiedName;
self.name = name;
self.bounds = bounds;
self.tags = tags;
self.parent = nil;
self.children = [NSArray array];
self.attributes = [NSDictionary dictionary];
}
return self;
}
@end
#endif

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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>
NS_ASSUME_NONNULL_BEGIN
@class UIDContext;
@interface UIDTreeObserver<__covariant T> : NSObject
@property(nonatomic, strong)
NSMutableDictionary<NSNumber*, UIDTreeObserver<T>*>* children;
@property(nonatomic, strong) NSString* type;
- (void)subscribe:(nullable T)node;
- (void)unsubscribe;
- (void)processNode:(id)node withContext:(UIDContext*)context;
- (void)processNode:(id)node
withSnapshot:(BOOL)snapshot
withContext:(UIDContext*)context;
- (void)cleanup;
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,75 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDTreeObserver.h"
#import "UIDContext.h"
#import "UIDHierarchyTraversal.h"
#import "UIDTimeUtilities.h"
@implementation UIDTreeObserver
- (instancetype)init {
self = [super init];
if (self) {
_children = [NSMutableDictionary new];
}
return self;
}
- (void)subscribe:(id)node {
}
- (void)unsubscribe {
}
- (void)processNode:(id)node withContext:(UIDContext*)context {
[self processNode:node withSnapshot:false withContext:context];
}
- (void)processNode:(id)node
withSnapshot:(BOOL)snapshot
withContext:(UIDContext*)context {
NSTimeInterval timestamp = UIDPerformanceTimeIntervalSince1970();
uint64_t t0 = UIDPerformanceNow();
UIDHierarchyTraversal* traversal = [UIDHierarchyTraversal
createWithDescriptorRegister:context.descriptorRegister];
UIDNodeDescriptor* descriptor =
[context.descriptorRegister descriptorForClass:[node class]];
UIDNodeDescriptor* rootDescriptor = [context.descriptorRegister
descriptorForClass:[context.application class]];
NSArray* nodes = [traversal traverse:node];
uint64_t t1 = UIDPerformanceNow();
UIImage* screenshot = [rootDescriptor snapshotForNode:context.application];
uint64_t t2 = UIDPerformanceNow();
UIDSubtreeUpdate* update = [UIDSubtreeUpdate new];
update.observerType = _type;
update.rootId = [descriptor identifierForNode:node];
update.nodes = nodes;
update.snapshot = screenshot;
update.timestamp = timestamp;
update.traversalMS = UIDMonotonicTimeConvertMachUnitsToMS(t1 - t0);
update.snapshotMS = UIDMonotonicTimeConvertMachUnitsToMS(t2 - t1);
[context.updateDigester digest:update];
}
- (void)cleanup {
}
@end
#endif

View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <Foundation/Foundation.h>
#import "UIDTreeObserver.h"
@class UIDContext;
/**
UIDTreeObserverBuilder, as the name suggests, can create an observers for a
node. Basically, observer builders are registered in the factory. Then, when
an observer is needed for a node, builders are asked whether they can create
an observer for it. If it can, then it will create an observer for it.
*/
@protocol UIDTreeObserverBuilder
- (BOOL)canBuildFor:(id)node;
- (UIDTreeObserver*)buildWithContext:(UIDContext*)context;
@end
#endif

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDTreeObserverBuilder.h"
NS_ASSUME_NONNULL_BEGIN
@class UIDContext;
/**
Factory of TreeObserver. It allows registration of different builders which
are the ones responsible of actually building observes for nodes.
*/
@interface UIDTreeObserverFactory : NSObject
+ (instancetype)shared;
- (void)registerBuilder:(id<UIDTreeObserverBuilder>)builder;
- (UIDTreeObserver*)createObserverForNode:(id)node
withContext:(UIDContext*)context;
- (BOOL)hasObserverForNode:(id)node;
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,66 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDTreeObserverFactory.h"
#import "UIDUIApplicationObserver.h"
@interface UIDTreeObserverFactory () {
NSMutableArray<id<UIDTreeObserverBuilder>>* _builders;
}
@end
@implementation UIDTreeObserverFactory
- (instancetype)init {
self = [super init];
if (self) {
_builders = [NSMutableArray new];
}
return self;
}
+ (instancetype)shared {
static UIDTreeObserverFactory* factory = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
factory = [UIDTreeObserverFactory new];
[factory registerBuilder:[UIDUIApplicationObserverBuilder new]];
});
return factory;
}
- (void)registerBuilder:(id<UIDTreeObserverBuilder>)builder {
[_builders addObject:builder];
}
- (UIDTreeObserver*)createObserverForNode:(id)node
withContext:(UIDContext*)context {
for (id<UIDTreeObserverBuilder> builder in _builders) {
if ([builder canBuildFor:node]) {
return [builder buildWithContext:context];
}
}
return nil;
}
- (BOOL)hasObserverForNode:(id)node {
for (id<UIDTreeObserverBuilder> builder in _builders) {
if ([builder canBuildFor:node]) {
return true;
}
}
return false;
}
@end
#endif

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class UIDContext;
@interface UIDTreeObserverManager : NSObject
+ (instancetype)shared;
- (void)startWithContext:(UIDContext*)context;
- (void)stop;
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,167 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDTreeObserverManager.h"
#import "UIDContext.h"
#import "UIDDescriptorRegister.h"
#import "UIDInitEvent.h"
#import "UIDJSONSerializer.h"
#import "UIDMetadataRegister.h"
#import "UIDMetadataUpdateEvent.h"
#import "UIDPerfStatsEvent.h"
#import "UIDPerformance.h"
#import "UIDSubtreeUpdateEvent.h"
#import "UIDTimeUtilities.h"
#import "UIDTreeObserverFactory.h"
@interface UIDTreeObserverManager ()<UIDUpdateDigester> {
dispatch_queue_t _queue;
UIDTreeObserver* _rootObserver;
UIDContext* _context;
}
@property(nonatomic, strong) UIDTreeObserver* viewObserver;
@end
@implementation UIDTreeObserverManager
- (instancetype)init {
self = [super init];
if (self) {
_queue =
dispatch_queue_create("ui-debugger.background", DISPATCH_QUEUE_SERIAL);
_context = nil;
}
return self;
}
+ (instancetype)shared {
static UIDTreeObserverManager* instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [UIDTreeObserverManager new];
});
return instance;
}
- (void)startWithContext:(UIDContext*)context {
_context = context;
_context.updateDigester = self;
[self sendInit];
if (!_rootObserver) {
_rootObserver =
[_context.observerFactory createObserverForNode:context.application
withContext:_context];
}
[_rootObserver subscribe:_context.application];
[_context.frameworkEventManager enable];
}
- (void)stop {
[_rootObserver unsubscribe];
[[UIDMetadataRegister shared] reset];
[_context.frameworkEventManager disable];
}
- (void)sendInit {
UIDNodeDescriptor* descriptor =
[_context.descriptorRegister descriptorForClass:[UIApplication class]];
UIDInitEvent* init = [UIDInitEvent new];
init.rootId = [descriptor identifierForNode:_context.application];
init.frameworkEventMetadata = [_context.frameworkEventManager eventsMetadata];
[_context.connection send:[UIDInitEvent name] withRawParams:UID_toJSON(init)];
}
- (void)sendMetadataUpdate {
NSDictionary* pendingMetadata =
[[UIDMetadataRegister shared] extractPendingMetadata];
if (![pendingMetadata count]) {
return;
}
UIDMetadataUpdateEvent* metadataUpdateEvent = [UIDMetadataUpdateEvent new];
metadataUpdateEvent.attributeMetadata = pendingMetadata;
id JSON = UID_toJSON(metadataUpdateEvent);
[_context.connection send:[UIDMetadataUpdateEvent name] withRawParams:JSON];
}
- (void)digest:(nonnull id<UIDUpdate>)update {
uint64_t t0 = UIDPerformanceNow();
dispatch_async(_queue, ^{
uint64_t t1 = UIDPerformanceNow();
UIDPerformanceClear();
UIDSubtreeUpdate* subtreeUpdate = (UIDSubtreeUpdate*)update;
UIDSubtreeUpdateEvent* subtreeUpdateEvent = [UIDSubtreeUpdateEvent new];
subtreeUpdateEvent.txId = UIDPerformanceTimeIntervalSince1970();
subtreeUpdateEvent.observerType = subtreeUpdate.observerType;
subtreeUpdateEvent.rootId = subtreeUpdate.rootId;
subtreeUpdateEvent.nodes = subtreeUpdate.nodes;
subtreeUpdateEvent.snapshot = subtreeUpdate.snapshot;
subtreeUpdateEvent.frameworkEvents =
[self->_context.frameworkEventManager events];
uint64_t t2 = UIDPerformanceNow();
id intermediate = UID_toFoundation(subtreeUpdateEvent);
uint64_t t3 = UIDPerformanceNow();
NSString* JSON = UID_FoundationtoJSON(intermediate);
uint64_t t4 = UIDPerformanceNow();
NSUInteger payloadSize = JSON.length;
[self sendMetadataUpdate];
[self->_context.connection send:[UIDSubtreeUpdateEvent name]
withRawParams:JSON];
uint64_t t5 = UIDPerformanceNow();
UIDPerfStatsEvent* perfStats = [UIDPerfStatsEvent new];
perfStats.txId = subtreeUpdateEvent.txId;
perfStats.observerType = subtreeUpdate.observerType;
perfStats.nodesCount = subtreeUpdate.nodes.count;
perfStats.eventsCount = subtreeUpdateEvent.frameworkEvents.count;
perfStats.start = UIDTimeIntervalToMS(subtreeUpdate.timestamp);
perfStats.traversalMS = subtreeUpdate.traversalMS;
perfStats.snapshotMS = subtreeUpdate.snapshotMS;
perfStats.queuingMS = UIDMonotonicTimeConvertMachUnitsToMS(t1 - t0);
perfStats.frameworkEventsMS = UIDMonotonicTimeConvertMachUnitsToMS(t2 - t1);
perfStats.deferredComputationMS =
UIDMonotonicTimeConvertMachUnitsToMS(t3 - t2);
perfStats.serializationMS = UIDMonotonicTimeConvertMachUnitsToMS(t4 - t3);
perfStats.socketMS = UIDMonotonicTimeConvertMachUnitsToMS(t5 - t4);
perfStats.payloadSize = payloadSize;
perfStats.dynamicMeasures = UIDPerformanceGet();
[self->_context.connection send:[UIDPerfStatsEvent name]
withRawParams:UID_toJSON(perfStats)];
});
}
@end
#endif

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDTreeObserverBuilder.h"
NS_ASSUME_NONNULL_BEGIN
@interface UIDUIApplicationObserver : UIDTreeObserver<UIApplication*>
@end
@interface UIDUIApplicationObserverBuilder : NSObject<UIDTreeObserverBuilder>
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,121 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDUIApplicationObserver.h"
#import "UIDContext.h"
#import "UIDMainThread.h"
#import "UIDUIViewBasicObserver.h"
#define UID_THROTTLE_SECONDS 1
@interface UIDUIApplicationObserver ()<UIDUIViewObserverDelegate> {
UIDContext* _context;
UIDUIViewBasicObserver* _viewObserver;
CFRunLoopObserverRef _observer;
NSTimeInterval _lastInvocationTimestamp;
bool _dirty;
}
@end
@implementation UIDUIApplicationObserver
- (instancetype)initWithContext:(UIDContext*)context {
self = [super init];
if (self) {
_context = context;
_lastInvocationTimestamp = 0;
_dirty = true;
_viewObserver = [[UIDUIViewBasicObserver alloc] initWithContext:_context
delegate:self];
self.type = @"UIApplication";
}
return self;
}
- (void)subscribe:(UIApplication*)node {
__weak typeof(self) weakSelf = self;
_observer = CFRunLoopObserverCreateWithHandler(
kCFAllocatorDefault,
kCFRunLoopBeforeWaiting,
true,
INT_MAX,
^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
typeof(self) strongSelf = weakSelf;
if (strongSelf) {
NSTimeInterval currentTimestamp =
[NSDate timeIntervalSinceReferenceDate];
if (strongSelf->_lastInvocationTimestamp == 0 ||
(currentTimestamp - strongSelf->_lastInvocationTimestamp >=
UID_THROTTLE_SECONDS)) {
strongSelf->_lastInvocationTimestamp = currentTimestamp;
if (strongSelf->_dirty) {
strongSelf->_dirty = false;
[self processNode:strongSelf->_context.application
withSnapshot:true
withContext:strongSelf->_context];
}
}
}
});
CFRunLoopAddObserver(CFRunLoopGetMain(), _observer, kCFRunLoopCommonModes);
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(orientationChanged:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
}
- (void)unsubscribe {
CFRunLoopRemoveObserver(CFRunLoopGetMain(), _observer, kCFRunLoopCommonModes);
CFRelease(_observer);
_observer = nil;
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:UIDeviceOrientationDidChangeNotification
object:nil];
_dirty = true;
}
- (void)orientationChanged:(NSNotification*)notification {
/**
Do not mark as dirty immediately as the view draws before
is animated into position. Dispatch after the same throttle amount
achieves the desired effect.
*/
UIDRunBlockOnMainThreadAfter(
^{
self->_dirty = true;
},
UID_THROTTLE_SECONDS);
}
- (void)viewUpdateWith:(UIView*)node {
_dirty = true;
}
@end
@implementation UIDUIApplicationObserverBuilder
- (BOOL)canBuildFor:(id)node {
return [node isKindOfClass:[UIApplication class]];
}
- (UIDTreeObserver*)buildWithContext:(UIDContext*)context {
return [[UIDUIApplicationObserver alloc] initWithContext:context];
}
@end
#endif

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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>
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSUInteger, UIDViewHierarchyUpdate) {
UIDViewHierarchyUpdateAddChild,
UIDViewHierarchyUpdateRemoveChild,
};
@protocol UIDUIKitObserverDelegate<NSObject>
- (void)onDisplayLayer:(UIView*)view;
- (void)onDrawLayer:(UIView*)view;
- (void)onNeedsDisplay:(UIView*)view;
- (void)onHidden:(UIView*)view;
- (void)onView:(UIView*)view didUpdateHierarchy:(UIDViewHierarchyUpdate)update;
@end
@interface UIDUIKitObserver : NSObject
+ (instancetype)sharedInstance;
+ (void)enable;
- (void)setDrawObservationEnabled:(BOOL)enabled;
@property(nonatomic, weak) id<UIDUIKitObserverDelegate> delegate;
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDUIKitObserver.h"
#import "UIView+Observer.h"
@implementation UIDUIKitObserver
+ (instancetype)sharedInstance {
static UIDUIKitObserver* instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [UIDUIKitObserver new];
});
return instance;
}
+ (void)enable {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[UIView UID_observe];
});
}
- (void)setDrawObservationEnabled:(BOOL)enabled {
[UIView UID_setDrawObservationEnabled:enabled];
}
@end
#endif

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <FlipperKit/SKMacros.h>
#import <UIKit/UIKit.h>
#import "UIDUIViewObserverDelegate.h"
NS_ASSUME_NONNULL_BEGIN
@class UIDContext;
@interface UIDUIViewBasicObserver : NSObject
- (instancetype)initWithContext:(UIDContext*)context
delegate:(id<UIDUIViewObserverDelegate>)delegate;
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDUIViewBasicObserver.h"
#import "UIDContext.h"
#import "UIDUIKitObserver.h"
@interface UIDUIViewBasicObserver ()<UIDUIKitObserverDelegate> {
UIDContext* _context;
}
@property(nonatomic, weak) id<UIDUIViewObserverDelegate> delegate;
@end
@implementation UIDUIViewBasicObserver
- (instancetype)initWithContext:(UIDContext*)context
delegate:(id<UIDUIViewObserverDelegate>)delegate {
self = [super init];
if (self) {
_context = context;
_delegate = delegate;
[UIDUIKitObserver sharedInstance].delegate = self;
[UIDUIKitObserver enable];
}
return self;
}
- (void)dealloc {
[UIDUIKitObserver sharedInstance].delegate = nil;
}
- (void)onDisplayLayer:(nonnull UIView*)view {
[self.delegate viewUpdateWith:view];
}
- (void)onDrawLayer:(nonnull UIView*)view {
[self.delegate viewUpdateWith:view];
}
- (void)onNeedsDisplay:(nonnull UIView*)view {
[self.delegate viewUpdateWith:view];
}
- (void)onHidden:(nonnull UIView*)view {
[self.delegate viewUpdateWith:view];
}
- (void)onView:(UIView*)view didUpdateHierarchy:(UIDViewHierarchyUpdate)update {
[self.delegate viewUpdateWith:view];
}
@end
#endif

View File

@@ -0,0 +1,16 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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>
@protocol UIDUIViewObserverDelegate<NSObject>
- (void)viewUpdateWith:(nonnull UIView*)view;
@end
#endif

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <FlipperKit/SKMacros.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
FB_LINK_REQUIRE_CATEGORY(UIView_Observer)
@interface UIView (Observer)
+ (void)UID_observe;
+ (void)UID_setDrawObservationEnabled:(BOOL)enabled;
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,158 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDSwizzle.h"
#import "UIDUIKitObserver.h"
#import "UIView+Observer.h"
static BOOL UID_DrawObserverEnabled = true;
FB_LINKABLE(UIView_Observer)
@implementation UIView (Observer)
+ (void)UID_setDrawObservationEnabled:(BOOL)enabled {
UID_DrawObserverEnabled = enabled;
}
+ (void)UID_observe {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
UIDSwizzleMethod(
[self class],
@selector(drawLayer:inContext:),
@selector(UID_drawLayer:inContext:),
false);
UIDSwizzleMethod(
[self class],
@selector(displayLayer:),
@selector(UID_displayLayer:),
false);
UIDSwizzleMethod(
[self class],
@selector(setNeedsDisplay),
@selector(UID_setNeedsDisplay),
false);
UIDSwizzleMethod(
[self class],
@selector(addSubview:),
@selector(UID_addSubview:),
false);
UIDSwizzleMethod(
[self class],
@selector(insertSubview:atIndex:),
@selector(UID_insertSubview:atIndex:),
false);
UIDSwizzleMethod(
[self class],
@selector(insertSubview:aboveSubview:),
@selector(UID_insertSubview:aboveSubview:),
false);
UIDSwizzleMethod(
[self class],
@selector(insertSubview:belowSubview:),
@selector(UID_insertSubview:belowSubview:),
false);
UIDSwizzleMethod(
[self class],
@selector(removeFromSuperview),
@selector(UID_removeFromSuperview),
false);
UIDSwizzleMethod(
[self class], @selector(setHidden:), @selector(UID_setHidden:), true);
});
}
- (void)UID_displayLayer:(CALayer*)layer {
[self UID_displayLayer:layer];
if (UID_DrawObserverEnabled) {
[[UIDUIKitObserver sharedInstance].delegate onDisplayLayer:self];
}
}
- (void)UID_drawLayer:(CALayer*)layer inContext:(CGContextRef)ctx {
[self UID_drawLayer:layer inContext:ctx];
if (UID_DrawObserverEnabled) {
[[UIDUIKitObserver sharedInstance].delegate onDrawLayer:self];
}
}
- (void)UID_setNeedsDisplay {
[self UID_setNeedsDisplay];
if (UID_DrawObserverEnabled) {
[[UIDUIKitObserver sharedInstance].delegate onNeedsDisplay:self];
}
}
- (void)UID_setHidden:(BOOL)isHidden {
[self UID_setHidden:isHidden];
if (UID_DrawObserverEnabled) {
[[UIDUIKitObserver sharedInstance].delegate onHidden:self];
}
}
- (void)UID_addSubview:(UIView*)view {
[self UID_addSubview:view];
if (UID_DrawObserverEnabled) {
[[UIDUIKitObserver sharedInstance].delegate
onView:self
didUpdateHierarchy:UIDViewHierarchyUpdateAddChild];
}
}
- (void)UID_insertSubview:(UIView*)subview atIndex:(NSInteger)index {
[self UID_insertSubview:subview atIndex:index];
if (UID_DrawObserverEnabled) {
[[UIDUIKitObserver sharedInstance].delegate
onView:self
didUpdateHierarchy:UIDViewHierarchyUpdateAddChild];
}
}
- (void)UID_insertSubview:(UIView*)subview
aboveSubview:(UIView*)siblingSubview {
[self UID_insertSubview:subview aboveSubview:siblingSubview];
if (UID_DrawObserverEnabled) {
[[UIDUIKitObserver sharedInstance].delegate
onView:self
didUpdateHierarchy:UIDViewHierarchyUpdateAddChild];
}
}
- (void)UID_insertSubview:(UIView*)subview
belowSubview:(UIView*)siblingSubview {
[self UID_insertSubview:subview belowSubview:siblingSubview];
if (UID_DrawObserverEnabled) {
[[UIDUIKitObserver sharedInstance].delegate
onView:self
didUpdateHierarchy:UIDViewHierarchyUpdateAddChild];
}
}
- (void)UID_removeFromSuperview {
UIView* oldSuperview = self.superview;
[self UID_removeFromSuperview];
/**
Not enough to check if draw observation is enabled (which is disabled
during snapshots). An extra check is needed in case the old superview is
_UISnapshotWindow_. The reason is _UIView_removeFromSuperview_ can also be
called during deallocation after the screenshot is taken and observation is
re-enabled. Without the extra check, it creates a recursive loop in which
the view is constantly marked as dirty.
*/
if (UID_DrawObserverEnabled &&
![oldSuperview isKindOfClass:NSClassFromString(@"_UISnapshotWindow")]) {
[[UIDUIKitObserver sharedInstance].delegate
onView:oldSuperview
didUpdateHierarchy:UIDViewHierarchyUpdateRemoveChild];
}
}
@end
#endif

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <FlipperKit/SKMacros.h>
#import <Foundation/Foundation.h>
#import "UIDFoundation.h"
NS_ASSUME_NONNULL_BEGIN
FB_LINK_REQUIRE_CATEGORY(NSArray_Foundation)
@interface NSArray<UIDFoundation>(Foundation)<UIDFoundation>
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "NSArray+Foundation.h"
FB_LINKABLE(NSArray_Foundation)
@implementation NSArray (Foundation)
- (id)toFoundation {
NSMutableArray* copy = [NSMutableArray arrayWithCapacity:self.count];
for (id<UIDFoundation> object in self) {
[copy addObject:[object toFoundation]];
}
return copy;
}
@end
#endif

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <FlipperKit/SKMacros.h>
#import <Foundation/Foundation.h>
#import "UIDFoundation.h"
NS_ASSUME_NONNULL_BEGIN
FB_LINK_REQUIRE_CATEGORY(NSDictionary_Foundation)
@interface NSDictionary (Foundation)<UIDFoundation>
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "NSDictionary+Foundation.h"
FB_LINKABLE(NSDictionary_Foundation)
@implementation NSDictionary (Foundation)
- (id)toFoundation {
NSMutableDictionary* copy =
[NSMutableDictionary dictionaryWithCapacity:self.count];
for (id key in self) {
[copy setObject:[self[key] toFoundation] forKey:[key description]];
}
return copy;
}
@end
#endif

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <FlipperKit/SKMacros.h>
#import <Foundation/Foundation.h>
#import "UIDFoundation.h"
NS_ASSUME_NONNULL_BEGIN
FB_LINK_REQUIRE_CATEGORY(NSNull_Foundation)
@interface NSNull (Foundation)<UIDFoundation>
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,21 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "NSNull+Foundation.h"
FB_LINKABLE(NSNull_Foundation)
@implementation NSNull (Foundation)
- (id)toFoundation {
return self;
}
@end
#endif

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <FlipperKit/SKMacros.h>
#import <Foundation/Foundation.h>
#import "UIDFoundation.h"
NS_ASSUME_NONNULL_BEGIN
FB_LINK_REQUIRE_CATEGORY(NSSet_Foundation)
@interface NSSet<UIDFoundation>(Foundation)<UIDFoundation>
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "NSSet+Foundation.h"
FB_LINKABLE(NSSet_Foundation)
@implementation NSSet (Foundation)
- (id)toFoundation {
NSMutableArray* copy = [NSMutableArray arrayWithCapacity:self.count];
for (id<UIDFoundation> object in self) {
[copy addObject:[object toFoundation]];
}
return copy;
}
@end
#endif

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <FlipperKit/SKMacros.h>
#import <Foundation/Foundation.h>
#import "UIDFoundation.h"
NS_ASSUME_NONNULL_BEGIN
FB_LINK_REQUIRE_CATEGORY(NSString_Foundation)
@interface NSString (Foundation)<UIDFoundation>
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,21 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "NSString+Foundation.h"
FB_LINKABLE(NSString_Foundation)
@implementation NSString (Foundation)
- (id)toFoundation {
return self;
}
@end
#endif

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <FlipperKit/SKMacros.h>
#import <Foundation/Foundation.h>
#import "UIDFoundation.h"
NS_ASSUME_NONNULL_BEGIN
FB_LINK_REQUIRE_CATEGORY(NSValue_Foundation)
@interface NSValue (Foundation)<UIDFoundation>
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,21 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "NSValue+Foundation.h"
FB_LINKABLE(NSValue_Foundation)
@implementation NSValue (Foundation)
- (id)toFoundation {
return self;
}
@end
#endif

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <FlipperKit/SKMacros.h>
#import <Foundation/Foundation.h>
#import "UIDBounds.h"
#import "UIDFoundation.h"
NS_ASSUME_NONNULL_BEGIN
FB_LINK_REQUIRE_CATEGORY(UIDBounds_Foundation)
@interface UIDBounds (Foundation)<UIDFoundation>
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDBounds+Foundation.h"
FB_LINKABLE(UIDBounds_Foundation)
@implementation UIDBounds (Foundation)
- (id)toFoundation {
return @{
@"x" : [NSNumber numberWithInt:self.x],
@"y" : [NSNumber numberWithInt:self.y],
@"width" : [NSNumber numberWithInt:self.width],
@"height" : [NSNumber numberWithInt:self.height],
};
}
@end
#endif

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <FlipperKit/SKMacros.h>
#import <UIKit/UIKit.h>
#import "UIDEdgeInsets.h"
#import "UIDFoundation.h"
NS_ASSUME_NONNULL_BEGIN
FB_LINK_REQUIRE_CATEGORY(UIDEdgeInsets_Foundation)
@interface UIDEdgeInsets (Foundation)<UIDFoundation>
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDEdgeInsets+Foundation.h"
FB_LINKABLE(UIDEdgeInsets_Foundation)
@implementation UIDEdgeInsets (Foundation)
- (id)toFoundation {
return @{
@"top" : [NSNumber numberWithFloat:self.top],
@"right" : [NSNumber numberWithFloat:self.right],
@"bottom" : [NSNumber numberWithFloat:self.bottom],
@"left" : [NSNumber numberWithFloat:self.left],
};
}
@end
#endif

View File

@@ -0,0 +1,16 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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
@protocol UIDFoundation
- (id)toFoundation;
@end
#endif

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <FlipperKit/SKMacros.h>
#import <Foundation/Foundation.h>
#import "UIDFoundation.h"
#import "UIDFrameworkEvent.h"
NS_ASSUME_NONNULL_BEGIN
FB_LINK_REQUIRE_CATEGORY(UIDFrameworkEvent_Foundation)
@interface UIDFrameworkEvent (Foundation)<UIDFoundation>
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDFrameworkEvent+Foundation.h"
FB_LINKABLE(UIDFrameworkEvent_Foundation)
@implementation UIDFrameworkEvent (Foundation)
- (id)toFoundation {
NSMutableDictionary* data = [NSMutableDictionary dictionaryWithDictionary:@{
@"nodeId" : [NSNumber numberWithUnsignedInt:self.nodeIdentifier],
@"type" : self.type,
@"timestamp" :
[NSNumber numberWithDouble:self.timestamp.timeIntervalSince1970],
@"payload" : self.payload ?: @{},
}];
if (self.stacktrace) {
[data setObject:@{@"stacktrace" : self.stacktrace, @"type" : @"stacktrace"}
forKey:@"attribution"];
}
return data;
}
@end
#endif

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <FlipperKit/SKMacros.h>
#import <Foundation/Foundation.h>
#import "UIDFoundation.h"
#import "UIDFrameworkEventMetadata.h"
NS_ASSUME_NONNULL_BEGIN
FB_LINK_REQUIRE_CATEGORY(UIDFrameworkEventMetadata_Foundation)
@interface UIDFrameworkEventMetadata (Foundation)<UIDFoundation>
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "NSDictionary+Foundation.h"
#import "UIDFrameworkEventMetadata+Foundation.h"
FB_LINKABLE(UIDFrameworkEventMetadata_Foundation)
@implementation UIDFrameworkEventMetadata (Foundation)
- (id)toFoundation {
return @{
@"type" : self.type,
@"documentation" : self.documentation,
};
}
@end
#endif

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <FlipperKit/SKMacros.h>
#import <Foundation/Foundation.h>
#import "UIDFoundation.h"
#import "UIDInitEvent.h"
NS_ASSUME_NONNULL_BEGIN
FB_LINK_REQUIRE_CATEGORY(UIDInitEvent_Foundation)
@interface UIDInitEvent (Foundation)<UIDFoundation>
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "NSArray+Foundation.h"
#import "UIDInitEvent+Foundation.h"
FB_LINKABLE(UIDInitEvent_Foundation)
@implementation UIDInitEvent (Foundation)
- (id)toFoundation {
return @{
@"rootId" : [NSNumber numberWithUnsignedInt:self.rootId],
@"frameworkEventMetadata" : self.frameworkEventMetadata
? [self.frameworkEventMetadata toFoundation]
: @[],
};
}
@end
#endif

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <FlipperKit/SKMacros.h>
#import <Foundation/Foundation.h>
#import "UIDFoundation.h"
#import "UIDInspectable.h"
NS_ASSUME_NONNULL_BEGIN
FB_LINK_REQUIRE_CATEGORY(UIDInspectable_Foundation)
@interface UIDInspectable (Foundation)<UIDFoundation>
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,21 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDInspectable+Foundation.h"
FB_LINKABLE(UIDInspectable_Foundation)
@implementation UIDInspectable (Foundation)
- (id)toFoundation {
return @{};
}
@end
#endif

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <FlipperKit/SKMacros.h>
#import <Foundation/Foundation.h>
#import "UIDFoundation.h"
#import "UIDInspectable.h"
NS_ASSUME_NONNULL_BEGIN
FB_LINK_REQUIRE_CATEGORY(UIDInspectableArray_Foundation)
@interface UIDInspectableArray (Foundation)<UIDFoundation>
@end
NS_ASSUME_NONNULL_END
#endif

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "UIDInspectable+Foundation.h"
#import "UIDInspectableArray+Foundation.h"
FB_LINKABLE(UIDInspectableArray_Foundation)
@implementation UIDInspectableArray (Foundation)
- (id)toFoundation {
NSMutableArray* items = [NSMutableArray arrayWithCapacity:self.items.count];
for (UIDInspectable* object in self.items) {
[items addObject:[object toFoundation]];
}
return @{@"type" : @"array", @"items" : items};
}
@end
#endif

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