143 lines
4.1 KiB
Mathematica
143 lines
4.1 KiB
Mathematica
|
|
/**
|
||
|
|
* Copyright (c) 2018-present, Facebook, Inc.
|
||
|
|
* All rights reserved.
|
||
|
|
*
|
||
|
|
* This source code is licensed under the BSD-style license found in the
|
||
|
|
* LICENSE file in the root directory of this source tree.
|
||
|
|
*/
|
||
|
|
|
||
|
|
#import "FBTVNavigationTracker.h"
|
||
|
|
#import "FBTVNavigationTracker-Private.h"
|
||
|
|
|
||
|
|
#import "FBMathUtils.h"
|
||
|
|
#import "XCUIElement+FBCaching.h"
|
||
|
|
#import "XCUIElement+FBUtilities.h"
|
||
|
|
#import "XCUIElement+FBWebDriverAttributes.h"
|
||
|
|
#import "XCUIApplication+FBHelpers.h"
|
||
|
|
|
||
|
|
#if TARGET_OS_TV
|
||
|
|
|
||
|
|
@implementation FBTVNavigationItem
|
||
|
|
|
||
|
|
+ (instancetype)itemWithUid:(NSString *) uid
|
||
|
|
{
|
||
|
|
return [[FBTVNavigationItem alloc] initWithUid:uid];
|
||
|
|
}
|
||
|
|
|
||
|
|
- (instancetype)initWithUid:(NSString *) uid
|
||
|
|
{
|
||
|
|
self = [super init];
|
||
|
|
if(self) {
|
||
|
|
_uid = uid;
|
||
|
|
_directions = [NSMutableSet set];
|
||
|
|
}
|
||
|
|
return self;
|
||
|
|
}
|
||
|
|
|
||
|
|
@end
|
||
|
|
|
||
|
|
@interface FBTVNavigationTracker ()
|
||
|
|
@property (nonatomic, strong) XCUIElement *targetElement;
|
||
|
|
@property (nonatomic, assign) CGPoint targetCenter;
|
||
|
|
@property (nonatomic, strong) NSMutableDictionary<NSString *, FBTVNavigationItem* >* navigationItems;
|
||
|
|
@end
|
||
|
|
|
||
|
|
@implementation FBTVNavigationTracker
|
||
|
|
|
||
|
|
+ (instancetype)trackerWithTargetElement:(XCUIElement *)targetElement
|
||
|
|
{
|
||
|
|
FBTVNavigationTracker *tracker = [[FBTVNavigationTracker alloc] initWithTargetElement:targetElement];
|
||
|
|
tracker.targetElement = targetElement;
|
||
|
|
return tracker;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (instancetype)initWithTargetElement:(XCUIElement *)targetElement
|
||
|
|
{
|
||
|
|
self = [super init];
|
||
|
|
if (self) {
|
||
|
|
_targetElement = targetElement;
|
||
|
|
CGRect frame = targetElement.wdFrame;
|
||
|
|
_targetCenter = FBRectGetCenter(frame);
|
||
|
|
_navigationItems = [NSMutableDictionary dictionary];
|
||
|
|
}
|
||
|
|
return self;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (FBTVDirection)directionToFocusedElement
|
||
|
|
{
|
||
|
|
XCUIElement *focused = XCUIApplication.fb_activeApplication.fb_focusedElement;
|
||
|
|
|
||
|
|
CGPoint focusedCenter = FBRectGetCenter(focused.wdFrame);
|
||
|
|
FBTVNavigationItem *item = [self navigationItemWithElement:focused];
|
||
|
|
CGFloat yDelta = self.targetCenter.y - focusedCenter.y;
|
||
|
|
CGFloat xDelta = self.targetCenter.x - focusedCenter.x;
|
||
|
|
FBTVDirection direction;
|
||
|
|
if (fabs(yDelta) > fabs(xDelta)) {
|
||
|
|
direction = [self verticalDirectionWithItem:item andDelta:yDelta];
|
||
|
|
if (direction == FBTVDirectionNone) {
|
||
|
|
direction = [self horizontalDirectionWithItem:item andDelta:xDelta];
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
direction = [self horizontalDirectionWithItem:item andDelta:xDelta];
|
||
|
|
if (direction == FBTVDirectionNone) {
|
||
|
|
direction = [self verticalDirectionWithItem:item andDelta:yDelta];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return direction;
|
||
|
|
}
|
||
|
|
|
||
|
|
#pragma mark - Utilities
|
||
|
|
- (FBTVNavigationItem*)navigationItemWithElement:(id<FBElement>)element
|
||
|
|
{
|
||
|
|
NSString *uid = element.wdUID;
|
||
|
|
if (nil == uid) {
|
||
|
|
return nil;
|
||
|
|
}
|
||
|
|
|
||
|
|
FBTVNavigationItem* item = [self.navigationItems objectForKey:uid];
|
||
|
|
if (nil != item) {
|
||
|
|
return item;
|
||
|
|
}
|
||
|
|
|
||
|
|
item = [FBTVNavigationItem itemWithUid:uid];
|
||
|
|
[self.navigationItems setObject:item forKey:uid];
|
||
|
|
return item;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (FBTVDirection)horizontalDirectionWithItem:(FBTVNavigationItem *)item andDelta:(CGFloat)delta
|
||
|
|
{
|
||
|
|
// GCFloat is double in 64bit. tvOS is only for arm64
|
||
|
|
if (delta > DBL_EPSILON &&
|
||
|
|
![item.directions containsObject: [NSNumber numberWithInteger: FBTVDirectionRight]]) {
|
||
|
|
[item.directions addObject: [NSNumber numberWithInteger: FBTVDirectionRight]];
|
||
|
|
return FBTVDirectionRight;
|
||
|
|
}
|
||
|
|
if (delta < -DBL_EPSILON &&
|
||
|
|
![item.directions containsObject: [NSNumber numberWithInteger: FBTVDirectionLeft]]) {
|
||
|
|
[item.directions addObject: [NSNumber numberWithInteger: FBTVDirectionLeft]];
|
||
|
|
return FBTVDirectionLeft;
|
||
|
|
}
|
||
|
|
return FBTVDirectionNone;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (FBTVDirection)verticalDirectionWithItem:(FBTVNavigationItem *)item andDelta:(CGFloat)delta
|
||
|
|
{
|
||
|
|
// GCFloat is double in 64bit. tvOS is only for arm64
|
||
|
|
if (delta > DBL_EPSILON &&
|
||
|
|
![item.directions containsObject: [NSNumber numberWithInteger: FBTVDirectionDown]]) {
|
||
|
|
[item.directions addObject: [NSNumber numberWithInteger: FBTVDirectionDown]];
|
||
|
|
return FBTVDirectionDown;
|
||
|
|
}
|
||
|
|
if (delta < -DBL_EPSILON &&
|
||
|
|
![item.directions containsObject: [NSNumber numberWithInteger: FBTVDirectionUp]]) {
|
||
|
|
[item.directions addObject: [NSNumber numberWithInteger: FBTVDirectionUp]];
|
||
|
|
return FBTVDirectionUp;
|
||
|
|
}
|
||
|
|
return FBTVDirectionNone;
|
||
|
|
}
|
||
|
|
|
||
|
|
@end
|
||
|
|
|
||
|
|
#endif
|