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