Swiftgram/Source/tvOS/ASImageNode+tvOS.mm
Adlai Holler d0ba092a77
Convert the codebase to Objective-C++ (#1206)
* Convert the codebase to Objective-C++ throughout. One language is better than two.

* Put it back

* Fix linker

* Point explicitly to updated Weaver to unblock build

* Revert "Point explicitly to updated Weaver to unblock build"

This reverts commit fdc25296e8794d4e6e56c35f5fe6da2be3f71dbc.

* Revert "Fix linker"

This reverts commit 7be25f91519b8497ef42de79f115bcfbdb965c39.

* Add in the frameworks

* no message

* Address spec lint warnings

* Fix tvos build

* Put that back

* Address Michael's review

* Add comment to kick CI
2018-11-02 12:04:14 -07:00

192 lines
6.4 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// ASImageNode+tvOS.mm
// Texture
//
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
//
#import <Foundation/Foundation.h>
#if TARGET_OS_TV
#import <AsyncDisplayKit/ASImageNode.h>
#import <AsyncDisplayKit/ASDisplayNode+Subclasses.h>
// TODO: Remove this we don't need to link GLKit just to convert degrees to radians.
#import <GLKit/GLKit.h>
#import <tgmath.h>
#import <AsyncDisplayKit/ASDisplayNodeExtras.h>
@implementation ASImageNode (tvOS)
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
self.isDefaultFocusAppearance = NO;
UIView *view = [self getView];
CALayer *layer = view.layer;
CGSize targetShadowOffset = CGSizeMake(0.0, self.bounds.size.height/8);
[layer removeAllAnimations];
[CATransaction begin];
[CATransaction setCompletionBlock:^{
layer.shadowOffset = targetShadowOffset;
}];
CABasicAnimation *shadowOffsetAnimation = [CABasicAnimation animationWithKeyPath:@"shadowOffset"];
shadowOffsetAnimation.toValue = [NSValue valueWithCGSize:targetShadowOffset];
shadowOffsetAnimation.duration = 0.4;
shadowOffsetAnimation.removedOnCompletion = NO;
shadowOffsetAnimation.fillMode = kCAFillModeForwards;
shadowOffsetAnimation.timingFunction = [CAMediaTimingFunction functionWithName:@"easeOut"];
[layer addAnimation:shadowOffsetAnimation forKey:@"shadowOffset"];
[CATransaction commit];
CABasicAnimation *shadowOpacityAnimation = [CABasicAnimation animationWithKeyPath:@"shadowOpacity"];
shadowOpacityAnimation.toValue = [NSNumber numberWithFloat:0.45];
shadowOpacityAnimation.duration = 0.4;
shadowOpacityAnimation.removedOnCompletion = false;
shadowOpacityAnimation.fillMode = kCAFillModeForwards;
shadowOpacityAnimation.timingFunction = [CAMediaTimingFunction functionWithName:@"easeOut"];
[layer addAnimation:shadowOpacityAnimation forKey:@"shadowOpacityAnimation"];
view.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.25, 1.25);
[CATransaction commit];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
// TODO: Clean up, and improve visuals.
if (!self.isDefaultFocusAppearance) {
// This view may correspond to either self.view
// or our superview if we are in a ASCellNode
UIView *view = [self getView];
UITouch *touch = [touches anyObject];
// Get the specific point that was touched
// This is quite messy in it's current state so is not ready for production.
// The reason it is here is for others to contribute and to make it clear what is occuring.
// We get the touch location in self.view because
// we are operating in that coordinate system.
// BUT we apply our transforms to *view since we want to apply
// the transforms to the root view (L: 107)
CGPoint point = [touch locationInView:self.view];
CGFloat pitch = 0;
CGFloat yaw = 0;
BOOL topHalf = NO;
if (point.y > CGRectGetHeight(self.view.frame)) {
pitch = 15;
} else if (point.y < -CGRectGetHeight(self.view.frame)) {
pitch = -15;
} else {
pitch = (point.y/CGRectGetHeight(self.view.frame))*15;
}
if (pitch < 0) {
topHalf = YES;
}
if (point.x > CGRectGetWidth(self.view.frame)) {
yaw = 10;
} else if (point.x < -CGRectGetWidth(self.view.frame)) {
yaw = -10;
} else {
yaw = (point.x/CGRectGetWidth(self.view.frame))*10;
}
if (!topHalf) {
if (yaw > 0) {
yaw = -yaw;
} else {
yaw = fabs(yaw);
}
}
CATransform3D pitchTransform = CATransform3DMakeRotation(GLKMathDegreesToRadians(pitch),1.0,0.0,0.0);
CATransform3D yawTransform = CATransform3DMakeRotation(GLKMathDegreesToRadians(yaw),0.0,1.0,0.0);
CATransform3D transform = CATransform3DConcat(pitchTransform, yawTransform);
CATransform3D scaleAndTransform = CATransform3DConcat(transform, CATransform3DMakeAffineTransform(CGAffineTransformScale(CGAffineTransformIdentity, 1.25, 1.25)));
[UIView animateWithDuration:0.5 animations:^{
view.layer.transform = scaleAndTransform;
}];
} else {
[self setDefaultFocusAppearance];
}
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[super touchesEnded:touches withEvent:event];
[self finishTouches];
}
- (void)finishTouches
{
if (!self.isDefaultFocusAppearance) {
UIView *view = [self getView];
CALayer *layer = view.layer;
CGSize targetShadowOffset = CGSizeMake(0.0, self.bounds.size.height/8);
CATransform3D targetScaleTransform = CATransform3DMakeScale(1.2, 1.2, 1.2);
[CATransaction begin];
[CATransaction setCompletionBlock:^{
layer.shadowOffset = targetShadowOffset;
}];
[CATransaction commit];
[UIView animateWithDuration:0.4 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
view.layer.transform = targetScaleTransform;
} completion:^(BOOL finished) {
if (finished) {
[layer removeAnimationForKey:@"shadowOffset"];
[layer removeAnimationForKey:@"shadowOpacity"];
}
}];
} else {
[self setDefaultFocusAppearance];
}
}
- (void)setFocusedState
{
UIView *view = [self getView];
CALayer *layer = view.layer;
layer.shadowOffset = CGSizeMake(2, 10);
layer.shadowColor = [UIColor blackColor].CGColor;
layer.shadowRadius = 12.0;
layer.shadowOpacity = 0.45;
layer.shadowPath = [UIBezierPath bezierPathWithRect:self.layer.bounds].CGPath;
view.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.25, 1.25);
}
- (void)setDefaultFocusAppearance
{
UIView *view = [self getView];
CALayer *layer = view.layer;
view.transform = CGAffineTransformIdentity;
layer.shadowOpacity = 0;
layer.shadowOffset = CGSizeZero;
layer.shadowRadius = 0;
layer.shadowPath = nil;
[layer removeAnimationForKey:@"shadowOffset"];
[layer removeAnimationForKey:@"shadowOpacity"];
self.isDefaultFocusAppearance = YES;
}
- (UIView *)getView
{
// TODO: This needs to be re-visited to handle all possibilities.
// If we are inside a ASCellNode, then we need to apply our focus effects to the ASCellNode view/layer rather than the ASImageNode view/layer.
return ASDisplayNodeUltimateParentOfNode(self).view;
}
@end
#endif