1*232917c1SKudo Chien#import "EXAppLoadingProgressWindowController.h"
2*232917c1SKudo Chien
3*232917c1SKudo Chien#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*232917c1SKudo Chien
5efd75decSTomasz Sapeta#import <ExpoModulesCore/EXDefines.h>
69ef743bcSBartłomiej Bukowski
7bab1112dSTomasz Sapeta#if !defined(EX_DETACHED)
8c46d5aaeSBartłomiej Bukowski#import "Expo_Go-Swift.h"
9bab1112dSTomasz Sapeta#endif // !defined(EX_DETACHED)
101236efb4STomasz Sapeta
119ef743bcSBartłomiej Bukowski#import "EXUtil.h"
129ef743bcSBartłomiej Bukowski
139ef743bcSBartłomiej Bukowski@interface EXAppLoadingProgressWindowController ()
149ef743bcSBartłomiej Bukowski
159ef743bcSBartłomiej Bukowski@property (nonatomic, assign) BOOL enabled;
169ef743bcSBartłomiej Bukowski@property (nonatomic, strong) UIWindow *window;
179ef743bcSBartłomiej Bukowski@property (nonatomic, strong) UILabel *textLabel;
189ef743bcSBartłomiej Bukowski
199ef743bcSBartłomiej Bukowski@end
209ef743bcSBartłomiej Bukowski
219ef743bcSBartłomiej Bukowski@implementation EXAppLoadingProgressWindowController
229ef743bcSBartłomiej Bukowski
239ef743bcSBartłomiej Bukowski- (instancetype)initWithEnabled:(BOOL)enabled
249ef743bcSBartłomiej Bukowski{
259ef743bcSBartłomiej Bukowski  if (self = [super init]) {
269ef743bcSBartłomiej Bukowski    _enabled = enabled;
279ef743bcSBartłomiej Bukowski  }
289ef743bcSBartłomiej Bukowski  return self;
299ef743bcSBartłomiej Bukowski}
309ef743bcSBartłomiej Bukowski
319ef743bcSBartłomiej Bukowski- (void)show
329ef743bcSBartłomiej Bukowski{
33bab1112dSTomasz Sapeta#if !defined(EX_DETACHED)
349ef743bcSBartłomiej Bukowski  if (!_enabled) {
359ef743bcSBartłomiej Bukowski    return;
369ef743bcSBartłomiej Bukowski  }
379ef743bcSBartłomiej Bukowski
38efd75decSTomasz Sapeta  EX_WEAKIFY(self);
399ef743bcSBartłomiej Bukowski  dispatch_async(dispatch_get_main_queue(), ^{
40efd75decSTomasz Sapeta    EX_ENSURE_STRONGIFY(self);
419ef743bcSBartłomiej Bukowski    if (!self.window) {
429ef743bcSBartłomiej Bukowski      CGSize screenSize = [UIScreen mainScreen].bounds.size;
439ef743bcSBartłomiej Bukowski
4471ebd28eSCharlie Cruzan      int bottomInsets = EXSharedApplication().keyWindow.safeAreaInsets.bottom;
4576b4fe7aSBartłomiej Bukowski      self.window = [[UIWindow alloc] initWithFrame:CGRectMake(0,
4676b4fe7aSBartłomiej Bukowski                                                               screenSize.height - 36 - bottomInsets,
4776b4fe7aSBartłomiej Bukowski                                                               screenSize.width,
48892d420fSEric Samelson                                                               36 + bottomInsets)];
499ef743bcSBartłomiej Bukowski      self.window.windowLevel = UIWindowLevelStatusBar + 1;
50c46d5aaeSBartłomiej Bukowski      self.window.rootViewController = [EXAppLoadingProgressWindowViewController new];
51892d420fSEric Samelson      self.window.backgroundColor = [EXUtil colorWithRGB:0xfafafa];
529ef743bcSBartłomiej Bukowski
539ef743bcSBartłomiej Bukowski      UIView *containerView = [UIView new];
549ef743bcSBartłomiej Bukowski      [self.window addSubview:containerView];
559ef743bcSBartłomiej Bukowski
569ef743bcSBartłomiej Bukowski      CALayer *topBorderLayer = [CALayer layer];
579ef743bcSBartłomiej Bukowski      topBorderLayer.frame = CGRectMake(0, 0, screenSize.width, 1);
589ef743bcSBartłomiej Bukowski      topBorderLayer.backgroundColor = [EXUtil colorWithRGB:0xe3e3e3].CGColor;
599ef743bcSBartłomiej Bukowski      [containerView.layer addSublayer:topBorderLayer];
609ef743bcSBartłomiej Bukowski
619ef743bcSBartłomiej Bukowski      self.textLabel = [UILabel new];
629ef743bcSBartłomiej Bukowski      self.textLabel.frame = CGRectMake(10, 0, screenSize.width - 20, 36);
639ef743bcSBartłomiej Bukowski      self.textLabel.font = [UIFont systemFontOfSize:12];
649ef743bcSBartłomiej Bukowski      self.textLabel.textAlignment = NSTextAlignmentLeft;
659ef743bcSBartłomiej Bukowski      self.textLabel.textColor = [EXUtil colorWithRGB:0xa7a7a7];
669ef743bcSBartłomiej Bukowski      [containerView addSubview:self.textLabel];
679ef743bcSBartłomiej Bukowski    }
689ef743bcSBartłomiej Bukowski    self.textLabel.text =  @"Waiting for server ...";
699ef743bcSBartłomiej Bukowski    self.window.hidden = NO;
709ef743bcSBartłomiej Bukowski  });
71bab1112dSTomasz Sapeta#endif // !defined(EX_DETACHED)
729ef743bcSBartłomiej Bukowski}
739ef743bcSBartłomiej Bukowski
749ef743bcSBartłomiej Bukowski- (void)hide
759ef743bcSBartłomiej Bukowski{
76bab1112dSTomasz Sapeta#if !defined(EX_DETACHED)
779ef743bcSBartłomiej Bukowski  if (!_enabled) {
789ef743bcSBartłomiej Bukowski    return;
799ef743bcSBartłomiej Bukowski  }
809ef743bcSBartłomiej Bukowski
81efd75decSTomasz Sapeta  EX_WEAKIFY(self);
8237ed3460SEric Samelson  dispatch_async(dispatch_get_main_queue(), ^{
83efd75decSTomasz Sapeta    EX_ENSURE_STRONGIFY(self);
8464c37d52SBartłomiej Bukowski    if (self.window) {
859ef743bcSBartłomiej Bukowski      self.window.hidden = YES;
86c46d5aaeSBartłomiej Bukowski      // remove this window altogther to hand over the command over StatusBar rotation
87c46d5aaeSBartłomiej Bukowski      self.window = nil;
889ef743bcSBartłomiej Bukowski    }
8937ed3460SEric Samelson  });
90bab1112dSTomasz Sapeta#endif // !defined(EX_DETACHED)
9164c37d52SBartłomiej Bukowski}
929ef743bcSBartłomiej Bukowski
939ef743bcSBartłomiej Bukowski- (void)updateStatusWithProgress:(EXLoadingProgress *)progress
949ef743bcSBartłomiej Bukowski{
95bab1112dSTomasz Sapeta#if !defined(EX_DETACHED)
969ef743bcSBartłomiej Bukowski  if (!_enabled) {
979ef743bcSBartłomiej Bukowski    return;
989ef743bcSBartłomiej Bukowski  }
999ef743bcSBartłomiej Bukowski
10064c37d52SBartłomiej Bukowski  [self show];
10164c37d52SBartłomiej Bukowski
102efd75decSTomasz Sapeta  EX_WEAKIFY(self);
1039ef743bcSBartłomiej Bukowski  dispatch_async(dispatch_get_main_queue(), ^{
104efd75decSTomasz Sapeta    EX_ENSURE_STRONGIFY(self);
1059ef743bcSBartłomiej Bukowski    float progressPercent = ([progress.done floatValue] / [progress.total floatValue]);
1069ef743bcSBartłomiej Bukowski    self.textLabel.text = [NSString stringWithFormat:@"%@ %.2f%%", progress.status, progressPercent * 100];
1079ef743bcSBartłomiej Bukowski    [self.textLabel setNeedsDisplay];
1089ef743bcSBartłomiej Bukowski
1099ef743bcSBartłomiej Bukowski    // TODO: (@bbarthec) maybe it's better to show/hide this based on other thing than progress status reported by the fetcher?
1109ef743bcSBartłomiej Bukowski    self.window.hidden = !(progress.total.floatValue > 0);
1119ef743bcSBartłomiej Bukowski  });
112bab1112dSTomasz Sapeta#endif // !defined(EX_DETACHED)
1139ef743bcSBartłomiej Bukowski}
1149ef743bcSBartłomiej Bukowski
11557bba33fSEric Samelson- (void)updateStatus:(EXAppLoaderRemoteUpdateStatus)status
11657bba33fSEric Samelson{
117bab1112dSTomasz Sapeta#if !defined(EX_DETACHED)
11857bba33fSEric Samelson  if (!_enabled) {
11957bba33fSEric Samelson    return;
12057bba33fSEric Samelson  }
12157bba33fSEric Samelson
12257bba33fSEric Samelson  NSString *statusText = [[self class] _loadingViewTextForStatus:status];
12357bba33fSEric Samelson  if (!statusText) {
12457bba33fSEric Samelson    return;
12557bba33fSEric Samelson  }
12657bba33fSEric Samelson
12757bba33fSEric Samelson  [self show];
12857bba33fSEric Samelson
129efd75decSTomasz Sapeta  EX_WEAKIFY(self);
13057bba33fSEric Samelson  dispatch_async(dispatch_get_main_queue(), ^{
131efd75decSTomasz Sapeta    EX_ENSURE_STRONGIFY(self);
13257bba33fSEric Samelson    self.textLabel.text = statusText;
13357bba33fSEric Samelson    [self.textLabel setNeedsDisplay];
13457bba33fSEric Samelson  });
135bab1112dSTomasz Sapeta#endif // !defined(EX_DETACHED)
13657bba33fSEric Samelson}
13757bba33fSEric Samelson
13857bba33fSEric Samelson+ (nullable NSString *)_loadingViewTextForStatus:(EXAppLoaderRemoteUpdateStatus)status
13957bba33fSEric Samelson{
14057bba33fSEric Samelson  if (status == kEXAppLoaderRemoteUpdateStatusChecking) {
14157bba33fSEric Samelson    return @"Checking for new update...";
14257bba33fSEric Samelson  } else if (status == kEXAppLoaderRemoteUpdateStatusDownloading) {
14357bba33fSEric Samelson    return @"New update available, downloading...";
14457bba33fSEric Samelson  } else {
14557bba33fSEric Samelson    return nil;
14657bba33fSEric Samelson  }
14757bba33fSEric Samelson}
1489ef743bcSBartłomiej Bukowski
1499ef743bcSBartłomiej Bukowski@end
150