xref: /aosp_15_r20/external/skia/tools/skottie_ios_app/main.mm (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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