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