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