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