1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 | #import <React/RCTDevLoadingView.h>
|
9 |
|
10 | #import <QuartzCore/QuartzCore.h>
|
11 |
|
12 | #import <React/RCTBridge.h>
|
13 | #import <React/RCTDefines.h>
|
14 | #import <React/RCTModalHostViewController.h>
|
15 | #import <React/RCTUtils.h>
|
16 |
|
17 | #if RCT_DEV | RCT_ENABLE_LOADING_VIEW
|
18 |
|
19 | static BOOL isEnabled = YES;
|
20 |
|
21 | @implementation RCTDevLoadingView
|
22 | {
|
23 | UIWindow *_window;
|
24 | UILabel *_label;
|
25 | NSDate *_showDate;
|
26 | }
|
27 |
|
28 | @synthesize bridge = _bridge;
|
29 |
|
30 | RCT_EXPORT_MODULE()
|
31 |
|
32 | + (void)setEnabled:(BOOL)enabled
|
33 | {
|
34 | isEnabled = enabled;
|
35 | }
|
36 |
|
37 | + (BOOL)requiresMainQueueSetup
|
38 | {
|
39 | return YES;
|
40 | }
|
41 |
|
42 | - (void)setBridge:(RCTBridge *)bridge
|
43 | {
|
44 | _bridge = bridge;
|
45 |
|
46 | [[NSNotificationCenter defaultCenter] addObserver:self
|
47 | selector:@selector(hide)
|
48 | name:RCTJavaScriptDidLoadNotification
|
49 | object:nil];
|
50 | [[NSNotificationCenter defaultCenter] addObserver:self
|
51 | selector:@selector(hide)
|
52 | name:RCTJavaScriptDidFailToLoadNotification
|
53 | object:nil];
|
54 |
|
55 | if (bridge.loading) {
|
56 | [self showWithURL:bridge.bundleURL];
|
57 | }
|
58 | }
|
59 |
|
60 | RCT_EXPORT_METHOD(showMessage:(NSString *)message color:(UIColor *)color backgroundColor:(UIColor *)backgroundColor)
|
61 | {
|
62 | if (!isEnabled) {
|
63 | return;
|
64 | }
|
65 |
|
66 | dispatch_async(dispatch_get_main_queue(), ^{
|
67 | self->_showDate = [NSDate date];
|
68 | if (!self->_window && !RCTRunningInTestEnvironment()) {
|
69 | CGSize screenSize = [UIScreen mainScreen].bounds.size;
|
70 |
|
71 | if (@available(iOS 11.0, *)) {
|
72 | UIWindow *window = RCTSharedApplication().keyWindow;
|
73 | self->_window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, screenSize.width, window.safeAreaInsets.top + 30)];
|
74 | self->_label = [[UILabel alloc] initWithFrame:CGRectMake(0, window.safeAreaInsets.top, screenSize.width, 30)];
|
75 | } else {
|
76 | self->_window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, screenSize.width, 22)];
|
77 | self->_label = [[UILabel alloc] initWithFrame:self->_window.bounds];
|
78 | }
|
79 | [self->_window addSubview:self->_label];
|
80 | #if TARGET_OS_TV
|
81 | self->_window.windowLevel = UIWindowLevelNormal + 1;
|
82 | #else
|
83 | self->_window.windowLevel = UIWindowLevelStatusBar + 1;
|
84 | #endif
|
85 | // set a root VC so rotation is supported
|
86 | self->_window.rootViewController = [UIViewController new];
|
87 |
|
88 | self->_label.font = [UIFont monospacedDigitSystemFontOfSize:12.0
|
89 | weight:UIFontWeightRegular];
|
90 | self->_label.textAlignment = NSTextAlignmentCenter;
|
91 | }
|
92 |
|
93 | self->_label.text = message;
|
94 | self->_label.textColor = color;
|
95 | self->_window.backgroundColor = backgroundColor;
|
96 | self->_window.hidden = NO;
|
97 | });
|
98 | }
|
99 |
|
100 | RCT_EXPORT_METHOD(hide)
|
101 | {
|
102 | if (!isEnabled) {
|
103 | return;
|
104 | }
|
105 |
|
106 | dispatch_async(dispatch_get_main_queue(), ^{
|
107 | const NSTimeInterval MIN_PRESENTED_TIME = 0.6;
|
108 | NSTimeInterval presentedTime = [[NSDate date] timeIntervalSinceDate:self->_showDate];
|
109 | NSTimeInterval delay = MAX(0, MIN_PRESENTED_TIME - presentedTime);
|
110 | CGRect windowFrame = self->_window.frame;
|
111 | [UIView animateWithDuration:0.25
|
112 | delay:delay
|
113 | options:0
|
114 | animations:^{
|
115 | self->_window.frame = CGRectOffset(windowFrame, 0, -windowFrame.size.height);
|
116 | } completion:^(__unused BOOL finished) {
|
117 | self->_window.frame = windowFrame;
|
118 | self->_window.hidden = YES;
|
119 | self->_window = nil;
|
120 | }];
|
121 | });
|
122 | }
|
123 |
|
124 | - (void)showWithURL:(NSURL *)URL
|
125 | {
|
126 | UIColor *color;
|
127 | UIColor *backgroundColor;
|
128 | NSString *message;
|
129 | if (URL.fileURL) {
|
130 | // If dev mode is not enabled, we don't want to show this kind of notification
|
131 | #if !RCT_DEV
|
132 | return;
|
133 | #endif
|
134 | color = [UIColor whiteColor];
|
135 | backgroundColor = [UIColor blackColor];
|
136 | message = [NSString stringWithFormat:@"Connect to %@ to develop JavaScript.", RCT_PACKAGER_NAME];
|
137 | } else {
|
138 | color = [UIColor whiteColor];
|
139 | backgroundColor = [UIColor colorWithHue:1./3 saturation:1 brightness:.35 alpha:1];
|
140 | message = [NSString stringWithFormat:@"Loading from %@:%@...", URL.host, URL.port];
|
141 | }
|
142 |
|
143 | [self showMessage:message
|
144 | color:color
|
145 | backgroundColor:backgroundColor];
|
146 | }
|
147 |
|
148 | - (void)updateProgress:(RCTLoadingProgress *)progress
|
149 | {
|
150 | if (!progress) {
|
151 | return;
|
152 | }
|
153 | dispatch_async(dispatch_get_main_queue(), ^{
|
154 | self->_label.text = [progress description];
|
155 | });
|
156 | }
|
157 |
|
158 | @end
|
159 |
|
160 | #else
|
161 |
|
162 | @implementation RCTDevLoadingView
|
163 |
|
164 | + (NSString *)moduleName { return nil; }
|
165 | + (void)setEnabled:(BOOL)enabled { }
|
166 | - (void)showMessage:(NSString *)message color:(UIColor *)color backgroundColor:(UIColor *)backgroundColor { }
|
167 | - (void)showWithURL:(NSURL *)URL { }
|
168 | - (void)updateProgress:(RCTLoadingProgress *)progress { }
|
169 | - (void)hide { }
|
170 |
|
171 | @end
|
172 |
|
173 | #endif
|