Add custom actions to flipper inspector

Summary:
Now when we are simulating device running in VoiceOver mode while showing accessiblity hierarchy in flipper, we are getting correct hierarchy + getting production-like custom actions,

Instagram + Facebook feed is a good example of using accessiblity actions to avoid exposing individual buttons

Reviewed By: lblasa

Differential Revision: D49641875

fbshipit-source-id: 1153ec3bffc7110c4bfe702cbb5a6b729d91b9a3
This commit is contained in:
Sash Zats
2023-09-27 07:38:38 -07:00
committed by Facebook GitHub Bot
parent cb86f0f90b
commit d46a301929

View File

@@ -171,6 +171,7 @@ static UIDAttributes* _atrtibutesForNode(NSObject* node) {
static UIDMetadataId AccessibilityTraitsAttributeId; static UIDMetadataId AccessibilityTraitsAttributeId;
static UIDMetadataId AccessibilityViewIsModalAttributeId; static UIDMetadataId AccessibilityViewIsModalAttributeId;
static UIDMetadataId ShouldGroupAccessibilityChildrenAttributeId; static UIDMetadataId ShouldGroupAccessibilityChildrenAttributeId;
static UIDMetadataId AccessibilityCustomActions;
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{
UIDMetadataRegister* const metadataRegister = [UIDMetadataRegister shared]; UIDMetadataRegister* const metadataRegister = [UIDMetadataRegister shared];
@@ -227,6 +228,11 @@ static UIDAttributes* _atrtibutesForNode(NSObject* node) {
name:@"shouldGroupAccessibilityChildren" name:@"shouldGroupAccessibilityChildren"
isMutable:false isMutable:false
definedBy:AccessibilityAttributeId]; definedBy:AccessibilityAttributeId];
AccessibilityCustomActions = [[UIDMetadataRegister shared]
registerMetadataWithType:UIDEBUGGER_METADATA_TYPE_ATTRIBUTE
name:@"accessibilityCustomActions"
isMutable:false
definedBy:AccessibilityAttributeId];
}); });
NSMutableDictionary* const accessibilityAttributes = NSMutableDictionary* const accessibilityAttributes =
@@ -258,12 +264,46 @@ static UIDAttributes* _atrtibutesForNode(NSObject* node) {
[UIDInspectableBoolean fromBoolean:node.shouldGroupAccessibilityChildren]; [UIDInspectableBoolean fromBoolean:node.shouldGroupAccessibilityChildren];
accessibilityAttributes[AccessibilityTraitsAttributeId] = [UIDInspectableText accessibilityAttributes[AccessibilityTraitsAttributeId] = [UIDInspectableText
fromText:_descriptionFromTraits(node.accessibilityTraits, NO)]; fromText:_descriptionFromTraits(node.accessibilityTraits, NO)];
accessibilityAttributes[AccessibilityCustomActions] =
_accessibilityCustomActionsDescription(node.accessibilityCustomActions);
return @{ return @{
AccessibilityAttributeId : AccessibilityAttributeId :
[UIDInspectableObject fromFields:accessibilityAttributes] [UIDInspectableObject fromFields:accessibilityAttributes]
}; };
} }
static UIDInspectable* _accessibilityCustomActionsDescription(
NSArray<UIAccessibilityCustomAction*>* actions) {
NSMutableArray<UIDInspectable*>* const descriptions = [NSMutableArray new];
for (UIAccessibilityCustomAction* action in actions) {
[descriptions
addObject:[UIDInspectableText fromText:_descriptionFromAction(action)]];
}
if (descriptions.count == 0) {
return [UIDInspectableUnknown null];
} else {
return [UIDInspectableArray fromItems:descriptions];
}
}
static NSString* _descriptionFromAction(UIAccessibilityCustomAction* action) {
if (@available(iOS 13.0, *)) {
if (action.actionHandler) {
return @"(handled in block)";
}
}
Class cls = [action.target class];
return [NSString
stringWithFormat:@"%@ -[%@ (%p) %@]",
(action.attributedName.string ?: action.name),
cls ? NSStringFromClass(cls) : @"UNKNOWN_CLASS",
action.target ? action.target : @"NO_TARGET",
action.selector ? NSStringFromSelector(action.selector)
: @"NO_SELECTOR"];
}
static NSString* _Nullable _descriptionFromTraits( static NSString* _Nullable _descriptionFromTraits(
UIAccessibilityTraits traits, UIAccessibilityTraits traits,
BOOL emojiOnly) { BOOL emojiOnly) {