1#import <ExpoModulesCore/EXDefines.h>
2
3#if __has_include("Expo_Go-Swift.h")
4#import "Expo_Go-Swift.h"
5#else
6#import "ExpoKitApp-Swift.h"
7#endif
8
9#import "EXAppLoadingProgressWindowController.h"
10#import "EXUtil.h"
11
12@interface EXAppLoadingProgressWindowController ()
13
14@property (nonatomic, assign) BOOL enabled;
15@property (nonatomic, strong) UIWindow *window;
16@property (nonatomic, strong) UILabel *textLabel;
17
18@end
19
20@implementation EXAppLoadingProgressWindowController
21
22- (instancetype)initWithEnabled:(BOOL)enabled
23{
24  if (self = [super init]) {
25    _enabled = enabled;
26  }
27  return self;
28}
29
30- (void)show
31{
32  if (!_enabled) {
33    return;
34  }
35
36  EX_WEAKIFY(self);
37  dispatch_async(dispatch_get_main_queue(), ^{
38    EX_ENSURE_STRONGIFY(self);
39    if (!self.window) {
40      CGSize screenSize = [UIScreen mainScreen].bounds.size;
41
42      int bottomInsets = EXSharedApplication().keyWindow.safeAreaInsets.bottom;
43      self.window = [[UIWindow alloc] initWithFrame:CGRectMake(0,
44                                                               screenSize.height - 36 - bottomInsets,
45                                                               screenSize.width,
46                                                               36 + bottomInsets)];
47      self.window.windowLevel = UIWindowLevelStatusBar + 1;
48      self.window.rootViewController = [EXAppLoadingProgressWindowViewController new];
49      self.window.backgroundColor = [EXUtil colorWithRGB:0xfafafa];
50
51      UIView *containerView = [UIView new];
52      [self.window addSubview:containerView];
53
54      CALayer *topBorderLayer = [CALayer layer];
55      topBorderLayer.frame = CGRectMake(0, 0, screenSize.width, 1);
56      topBorderLayer.backgroundColor = [EXUtil colorWithRGB:0xe3e3e3].CGColor;
57      [containerView.layer addSublayer:topBorderLayer];
58
59      self.textLabel = [UILabel new];
60      self.textLabel.frame = CGRectMake(10, 0, screenSize.width - 20, 36);
61      self.textLabel.font = [UIFont systemFontOfSize:12];
62      self.textLabel.textAlignment = NSTextAlignmentLeft;
63      self.textLabel.textColor = [EXUtil colorWithRGB:0xa7a7a7];
64      [containerView addSubview:self.textLabel];
65    }
66    self.textLabel.text =  @"Waiting for server ...";
67    self.window.hidden = NO;
68  });
69}
70
71- (void)hide
72{
73  if (!_enabled) {
74    return;
75  }
76
77  EX_WEAKIFY(self);
78  dispatch_async(dispatch_get_main_queue(), ^{
79    EX_ENSURE_STRONGIFY(self);
80    if (self.window) {
81      self.window.hidden = YES;
82      // remove this window altogther to hand over the command over StatusBar rotation
83      self.window = nil;
84    }
85  });
86}
87
88- (void)updateStatusWithProgress:(EXLoadingProgress *)progress
89{
90  if (!_enabled) {
91    return;
92  }
93
94  [self show];
95
96  EX_WEAKIFY(self);
97  dispatch_async(dispatch_get_main_queue(), ^{
98    EX_ENSURE_STRONGIFY(self);
99    float progressPercent = ([progress.done floatValue] / [progress.total floatValue]);
100    self.textLabel.text = [NSString stringWithFormat:@"%@ %.2f%%", progress.status, progressPercent * 100];
101    [self.textLabel setNeedsDisplay];
102
103    // TODO: (@bbarthec) maybe it's better to show/hide this based on other thing than progress status reported by the fetcher?
104    self.window.hidden = !(progress.total.floatValue > 0);
105  });
106}
107
108- (void)updateStatus:(EXAppLoaderRemoteUpdateStatus)status
109{
110  if (!_enabled) {
111    return;
112  }
113
114  NSString *statusText = [[self class] _loadingViewTextForStatus:status];
115  if (!statusText) {
116    return;
117  }
118
119  [self show];
120
121  EX_WEAKIFY(self);
122  dispatch_async(dispatch_get_main_queue(), ^{
123    EX_ENSURE_STRONGIFY(self);
124    self.textLabel.text = statusText;
125    [self.textLabel setNeedsDisplay];
126  });
127}
128
129+ (nullable NSString *)_loadingViewTextForStatus:(EXAppLoaderRemoteUpdateStatus)status
130{
131  if (status == kEXAppLoaderRemoteUpdateStatusChecking) {
132    return @"Checking for new update...";
133  } else if (status == kEXAppLoaderRemoteUpdateStatusDownloading) {
134    return @"New update available, downloading...";
135  } else {
136    return nil;
137  }
138}
139
140@end
141