1*c8dee2aaSAndroid Build Coastguard Worker// Copyright 2019 Google LLC. 2*c8dee2aaSAndroid Build Coastguard Worker// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. 3*c8dee2aaSAndroid Build Coastguard Worker 4*c8dee2aaSAndroid Build Coastguard Worker#include "tools/skottie_ios_app/SkiaContext.h" 5*c8dee2aaSAndroid Build Coastguard Worker#include "tools/skottie_ios_app/SkottieViewController.h" 6*c8dee2aaSAndroid Build Coastguard Worker 7*c8dee2aaSAndroid Build Coastguard Worker#include "include/core/SkTypes.h" 8*c8dee2aaSAndroid Build Coastguard Worker 9*c8dee2aaSAndroid Build Coastguard Worker#import <UIKit/UIKit.h> 10*c8dee2aaSAndroid Build Coastguard Worker 11*c8dee2aaSAndroid Build Coastguard Worker#include <cstdlib> 12*c8dee2aaSAndroid Build Coastguard Worker 13*c8dee2aaSAndroid Build Coastguard Worker@interface AppViewController : UIViewController 14*c8dee2aaSAndroid Build Coastguard Worker @property (strong) SkiaContext* skiaContext; 15*c8dee2aaSAndroid Build Coastguard Worker @property (strong) UIStackView* stackView; 16*c8dee2aaSAndroid Build Coastguard Worker@end 17*c8dee2aaSAndroid Build Coastguard Worker 18*c8dee2aaSAndroid Build Coastguard Worker@implementation AppViewController 19*c8dee2aaSAndroid Build Coastguard Worker 20*c8dee2aaSAndroid Build Coastguard Worker- (void)loadView { 21*c8dee2aaSAndroid Build Coastguard Worker [self setView:[[UIView alloc] init]]; 22*c8dee2aaSAndroid Build Coastguard Worker} 23*c8dee2aaSAndroid Build Coastguard Worker 24*c8dee2aaSAndroid Build Coastguard Worker- (void)viewDidLoad { 25*c8dee2aaSAndroid Build Coastguard Worker [super viewDidLoad]; 26*c8dee2aaSAndroid Build Coastguard Worker if (![self skiaContext]) { 27*c8dee2aaSAndroid Build Coastguard Worker #if (defined(SK_GANESH) && defined(SK_METAL) && !defined(SK_BUILD_FOR_GOOGLE3)) 28*c8dee2aaSAndroid Build Coastguard Worker [self setSkiaContext:MakeSkiaMetalContext()]; 29*c8dee2aaSAndroid Build Coastguard Worker #elif (defined(SK_GANESH) && defined(SK_GL) && !defined(SK_BUILD_FOR_GOOGLE3)) 30*c8dee2aaSAndroid Build Coastguard Worker [self setSkiaContext:MakeSkiaGLContext()]; 31*c8dee2aaSAndroid Build Coastguard Worker #else 32*c8dee2aaSAndroid Build Coastguard Worker [self setSkiaContext:MakeSkiaUIContext()]; 33*c8dee2aaSAndroid Build Coastguard Worker #endif 34*c8dee2aaSAndroid Build Coastguard Worker if (![self skiaContext]) { 35*c8dee2aaSAndroid Build Coastguard Worker NSLog(@"abort: failed to make skia context."); 36*c8dee2aaSAndroid Build Coastguard Worker std::abort(); 37*c8dee2aaSAndroid Build Coastguard Worker } 38*c8dee2aaSAndroid Build Coastguard Worker } 39*c8dee2aaSAndroid Build Coastguard Worker CGFloat screenWidth = [[UIScreen mainScreen] bounds].size.width; 40*c8dee2aaSAndroid Build Coastguard Worker 41*c8dee2aaSAndroid Build Coastguard Worker UIStackView* stack = [[UIStackView alloc] init]; 42*c8dee2aaSAndroid Build Coastguard Worker [stack setAxis:UILayoutConstraintAxisVertical]; 43*c8dee2aaSAndroid Build Coastguard Worker [stack setDistribution:UIStackViewDistributionEqualSpacing]; 44*c8dee2aaSAndroid Build Coastguard Worker 45*c8dee2aaSAndroid Build Coastguard Worker NSBundle* mainBundle = [NSBundle mainBundle]; 46*c8dee2aaSAndroid Build Coastguard Worker NSArray<NSString*>* paths = [mainBundle pathsForResourcesOfType:@"json" 47*c8dee2aaSAndroid Build Coastguard Worker inDirectory:@"data"]; 48*c8dee2aaSAndroid Build Coastguard Worker constexpr CGFloat kSpacing = 2; 49*c8dee2aaSAndroid Build Coastguard Worker CGFloat totalHeight = kSpacing; 50*c8dee2aaSAndroid Build Coastguard Worker for (NSUInteger i = 0; i < [paths count]; ++i) { 51*c8dee2aaSAndroid Build Coastguard Worker NSString* path = [paths objectAtIndex:i]; 52*c8dee2aaSAndroid Build Coastguard Worker NSData* content = [NSData dataWithContentsOfFile:path]; 53*c8dee2aaSAndroid Build Coastguard Worker if (!content) { 54*c8dee2aaSAndroid Build Coastguard Worker NSLog(@"'%@' not found", path); 55*c8dee2aaSAndroid Build Coastguard Worker continue; 56*c8dee2aaSAndroid Build Coastguard Worker } 57*c8dee2aaSAndroid Build Coastguard Worker SkottieViewController* controller = [[SkottieViewController alloc] init]; 58*c8dee2aaSAndroid Build Coastguard Worker if (![controller loadAnimation:content]) { 59*c8dee2aaSAndroid Build Coastguard Worker continue; 60*c8dee2aaSAndroid Build Coastguard Worker } 61*c8dee2aaSAndroid Build Coastguard Worker CGSize animSize = [controller size]; 62*c8dee2aaSAndroid Build Coastguard Worker CGFloat height = animSize.width ? (screenWidth * animSize.height / animSize.width) : 0; 63*c8dee2aaSAndroid Build Coastguard Worker CGRect frame = {{0, 0}, {screenWidth, height}}; 64*c8dee2aaSAndroid Build Coastguard Worker UIView* skiaView = [[self skiaContext] makeViewWithController:controller withFrame:frame]; 65*c8dee2aaSAndroid Build Coastguard Worker [[[skiaView heightAnchor] constraintEqualToConstant:height] setActive:true]; 66*c8dee2aaSAndroid Build Coastguard Worker [[[skiaView widthAnchor] constraintEqualToConstant:screenWidth] setActive:true]; 67*c8dee2aaSAndroid Build Coastguard Worker [skiaView setNeedsDisplay]; 68*c8dee2aaSAndroid Build Coastguard Worker [stack addArrangedSubview:skiaView]; 69*c8dee2aaSAndroid Build Coastguard Worker totalHeight += height + kSpacing; 70*c8dee2aaSAndroid Build Coastguard Worker } 71*c8dee2aaSAndroid Build Coastguard Worker [stack setFrame:{{0, 0}, {screenWidth, totalHeight}}]; 72*c8dee2aaSAndroid Build Coastguard Worker [stack setNeedsDisplay]; 73*c8dee2aaSAndroid Build Coastguard Worker 74*c8dee2aaSAndroid Build Coastguard Worker CGFloat statusBarHeight = [[UIApplication sharedApplication] statusBarFrame].size.height; 75*c8dee2aaSAndroid Build Coastguard Worker CGSize mainScreenSize = [[UIScreen mainScreen] bounds].size; 76*c8dee2aaSAndroid Build Coastguard Worker CGRect scrollViewBounds = {{0, statusBarHeight}, 77*c8dee2aaSAndroid Build Coastguard Worker {mainScreenSize.width, mainScreenSize.height - statusBarHeight}}; 78*c8dee2aaSAndroid Build Coastguard Worker UIScrollView* scrollView = [[UIScrollView alloc] initWithFrame:scrollViewBounds]; 79*c8dee2aaSAndroid Build Coastguard Worker [scrollView setContentSize:[stack frame].size]; 80*c8dee2aaSAndroid Build Coastguard Worker [scrollView addSubview:stack]; 81*c8dee2aaSAndroid Build Coastguard Worker [scrollView setBackgroundColor:[UIColor blackColor]]; 82*c8dee2aaSAndroid Build Coastguard Worker [scrollView setNeedsDisplay]; 83*c8dee2aaSAndroid Build Coastguard Worker 84*c8dee2aaSAndroid Build Coastguard Worker [self setStackView:stack]; 85*c8dee2aaSAndroid Build Coastguard Worker 86*c8dee2aaSAndroid Build Coastguard Worker UIView* mainView = [self view]; 87*c8dee2aaSAndroid Build Coastguard Worker [mainView setBounds:{{0, 0}, mainScreenSize}]; 88*c8dee2aaSAndroid Build Coastguard Worker [mainView setBackgroundColor:[UIColor whiteColor]]; 89*c8dee2aaSAndroid Build Coastguard Worker [mainView addSubview:scrollView]; 90*c8dee2aaSAndroid Build Coastguard Worker [mainView setNeedsDisplay]; 91*c8dee2aaSAndroid Build Coastguard Worker 92*c8dee2aaSAndroid Build Coastguard Worker UITapGestureRecognizer* tapGestureRecognizer = [[UITapGestureRecognizer alloc] init]; 93*c8dee2aaSAndroid Build Coastguard Worker [tapGestureRecognizer addTarget:self action:@selector(handleTap:)]; 94*c8dee2aaSAndroid Build Coastguard Worker [mainView addGestureRecognizer:tapGestureRecognizer]; 95*c8dee2aaSAndroid Build Coastguard Worker} 96*c8dee2aaSAndroid Build Coastguard Worker 97*c8dee2aaSAndroid Build Coastguard Worker- (void)handleTap:(UIGestureRecognizer*)sender { 98*c8dee2aaSAndroid Build Coastguard Worker if ([sender state] != UIGestureRecognizerStateEnded) { 99*c8dee2aaSAndroid Build Coastguard Worker return; 100*c8dee2aaSAndroid Build Coastguard Worker } 101*c8dee2aaSAndroid Build Coastguard Worker NSArray<UIView*>* subviews = [[self stackView] subviews]; 102*c8dee2aaSAndroid Build Coastguard Worker for (NSUInteger i = 0; i < [subviews count]; ++i) { 103*c8dee2aaSAndroid Build Coastguard Worker UIView* uIView = [subviews objectAtIndex:i]; 104*c8dee2aaSAndroid Build Coastguard Worker if (SkiaViewController* controller = [[self skiaContext] getViewController:uIView]) { 105*c8dee2aaSAndroid Build Coastguard Worker [controller togglePaused]; 106*c8dee2aaSAndroid Build Coastguard Worker [uIView setNeedsDisplay]; 107*c8dee2aaSAndroid Build Coastguard Worker } 108*c8dee2aaSAndroid Build Coastguard Worker } 109*c8dee2aaSAndroid Build Coastguard Worker} 110*c8dee2aaSAndroid Build Coastguard Worker@end 111*c8dee2aaSAndroid Build Coastguard Worker 112*c8dee2aaSAndroid Build Coastguard Worker@interface AppDelegate : UIResponder <UIApplicationDelegate> 113*c8dee2aaSAndroid Build Coastguard Worker @property (strong, nonatomic) UIWindow* window; 114*c8dee2aaSAndroid Build Coastguard Worker@end 115*c8dee2aaSAndroid Build Coastguard Worker 116*c8dee2aaSAndroid Build Coastguard Worker@implementation AppDelegate 117*c8dee2aaSAndroid Build Coastguard Worker 118*c8dee2aaSAndroid Build Coastguard Worker- (BOOL)application:(UIApplication*)app didFinishLaunchingWithOptions:(NSDictionary*)ops { 119*c8dee2aaSAndroid Build Coastguard Worker [self setWindow:[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]]; 120*c8dee2aaSAndroid Build Coastguard Worker [[self window] setRootViewController:[[AppViewController alloc] init]]; 121*c8dee2aaSAndroid Build Coastguard Worker [[self window] makeKeyAndVisible]; 122*c8dee2aaSAndroid Build Coastguard Worker return YES; 123*c8dee2aaSAndroid Build Coastguard Worker} 124*c8dee2aaSAndroid Build Coastguard Worker@end 125*c8dee2aaSAndroid Build Coastguard Worker 126*c8dee2aaSAndroid Build Coastguard Workerint main(int argc, char* argv[]) { 127*c8dee2aaSAndroid Build Coastguard Worker @autoreleasepool { 128*c8dee2aaSAndroid Build Coastguard Worker return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 129*c8dee2aaSAndroid Build Coastguard Worker } 130*c8dee2aaSAndroid Build Coastguard Worker} 131