PageRenderTime 44ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/front/plugins/cordova-plugin-splashscreen/src/ios/CDVSplashScreen.m

https://gitlab.com/boxnia/NFU_MOVIL
Objective C | 461 lines | 338 code | 66 blank | 57 comment | 100 complexity | 26f280a843cf3908b174ae773b1dc6dc MD5 | raw file
  1. /*
  2. Licensed to the Apache Software Foundation (ASF) under one
  3. or more contributor license agreements. See the NOTICE file
  4. distributed with this work for additional information
  5. regarding copyright ownership. The ASF licenses this file
  6. to you under the Apache License, Version 2.0 (the
  7. "License"); you may not use this file except in compliance
  8. with the License. You may obtain a copy of the License at
  9. http://www.apache.org/licenses/LICENSE-2.0
  10. Unless required by applicable law or agreed to in writing,
  11. software distributed under the License is distributed on an
  12. "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  13. KIND, either express or implied. See the License for the
  14. specific language governing permissions and limitations
  15. under the License.
  16. */
  17. #import "CDVSplashScreen.h"
  18. #import <Cordova/CDVViewController.h>
  19. #import <Cordova/CDVScreenOrientationDelegate.h>
  20. #import "CDVViewController+SplashScreen.h"
  21. #define kSplashScreenDurationDefault 3000.0f
  22. @implementation CDVSplashScreen
  23. - (void)pluginInitialize
  24. {
  25. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pageDidLoad) name:CDVPageDidLoadNotification object:nil];
  26. [self setVisible:YES];
  27. }
  28. - (void)show:(CDVInvokedUrlCommand*)command
  29. {
  30. [self setVisible:YES];
  31. }
  32. - (void)hide:(CDVInvokedUrlCommand*)command
  33. {
  34. [self setVisible:NO];
  35. }
  36. - (void)pageDidLoad
  37. {
  38. id autoHideSplashScreenValue = [self.commandDelegate.settings objectForKey:[@"AutoHideSplashScreen" lowercaseString]];
  39. // if value is missing, default to yes
  40. if ((autoHideSplashScreenValue == nil) || [autoHideSplashScreenValue boolValue]) {
  41. [self setVisible:NO];
  42. }
  43. }
  44. - (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context
  45. {
  46. [self updateImage];
  47. }
  48. - (void)createViews
  49. {
  50. /*
  51. * The Activity View is the top spinning throbber in the status/battery bar. We init it with the default Grey Style.
  52. *
  53. * whiteLarge = UIActivityIndicatorViewStyleWhiteLarge
  54. * white = UIActivityIndicatorViewStyleWhite
  55. * gray = UIActivityIndicatorViewStyleGray
  56. *
  57. */
  58. // Determine whether rotation should be enabled for this device
  59. // Per iOS HIG, landscape is only supported on iPad and iPhone 6+
  60. CDV_iOSDevice device = [self getCurrentDevice];
  61. BOOL autorotateValue = (device.iPad || device.iPhone6Plus) ?
  62. [(CDVViewController *)self.viewController shouldAutorotateDefaultValue] :
  63. NO;
  64. [(CDVViewController *)self.viewController setEnabledAutorotation:autorotateValue];
  65. NSString* topActivityIndicator = [self.commandDelegate.settings objectForKey:[@"TopActivityIndicator" lowercaseString]];
  66. UIActivityIndicatorViewStyle topActivityIndicatorStyle = UIActivityIndicatorViewStyleGray;
  67. if ([topActivityIndicator isEqualToString:@"whiteLarge"])
  68. {
  69. topActivityIndicatorStyle = UIActivityIndicatorViewStyleWhiteLarge;
  70. }
  71. else if ([topActivityIndicator isEqualToString:@"white"])
  72. {
  73. topActivityIndicatorStyle = UIActivityIndicatorViewStyleWhite;
  74. }
  75. else if ([topActivityIndicator isEqualToString:@"gray"])
  76. {
  77. topActivityIndicatorStyle = UIActivityIndicatorViewStyleGray;
  78. }
  79. UIView* parentView = self.viewController.view;
  80. parentView.userInteractionEnabled = NO; // disable user interaction while splashscreen is shown
  81. _activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:topActivityIndicatorStyle];
  82. _activityView.center = CGPointMake(parentView.bounds.size.width / 2, parentView.bounds.size.height / 2);
  83. _activityView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin
  84. | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin;
  85. [_activityView startAnimating];
  86. // Set the frame & image later.
  87. _imageView = [[UIImageView alloc] init];
  88. [parentView addSubview:_imageView];
  89. id showSplashScreenSpinnerValue = [self.commandDelegate.settings objectForKey:[@"ShowSplashScreenSpinner" lowercaseString]];
  90. // backwards compatibility - if key is missing, default to true
  91. if ((showSplashScreenSpinnerValue == nil) || [showSplashScreenSpinnerValue boolValue])
  92. {
  93. [parentView addSubview:_activityView];
  94. }
  95. // Frame is required when launching in portrait mode.
  96. // Bounds for landscape since it captures the rotation.
  97. [parentView addObserver:self forKeyPath:@"frame" options:0 context:nil];
  98. [parentView addObserver:self forKeyPath:@"bounds" options:0 context:nil];
  99. [self updateImage];
  100. }
  101. - (void)hideViews
  102. {
  103. [_imageView setAlpha:0];
  104. [_activityView setAlpha:0];
  105. }
  106. - (void)destroyViews
  107. {
  108. [(CDVViewController *)self.viewController setEnabledAutorotation:[(CDVViewController *)self.viewController shouldAutorotateDefaultValue]];
  109. [_imageView removeFromSuperview];
  110. [_activityView removeFromSuperview];
  111. _imageView = nil;
  112. _activityView = nil;
  113. _curImageName = nil;
  114. self.viewController.view.userInteractionEnabled = YES; // re-enable user interaction upon completion
  115. [self.viewController.view removeObserver:self forKeyPath:@"frame"];
  116. [self.viewController.view removeObserver:self forKeyPath:@"bounds"];
  117. }
  118. - (CDV_iOSDevice) getCurrentDevice
  119. {
  120. CDV_iOSDevice device;
  121. UIScreen* mainScreen = [UIScreen mainScreen];
  122. CGFloat mainScreenHeight = mainScreen.bounds.size.height;
  123. CGFloat mainScreenWidth = mainScreen.bounds.size.width;
  124. int limit = MAX(mainScreenHeight,mainScreenWidth);
  125. device.iPad = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
  126. device.iPhone = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone);
  127. device.retina = ([mainScreen scale] == 2.0);
  128. device.iPhone4 = (device.iPhone && limit == 480.0);
  129. device.iPhone5 = (device.iPhone && limit == 568.0);
  130. // note these below is not a true device detect, for example if you are on an
  131. // iPhone 6/6+ but the app is scaled it will prob set iPhone5 as true, but
  132. // this is appropriate for detecting the runtime screen environment
  133. device.iPhone6 = (device.iPhone && limit == 667.0);
  134. device.iPhone6Plus = (device.iPhone && limit == 736.0);
  135. return device;
  136. }
  137. - (NSString*)getImageName:(UIInterfaceOrientation)currentOrientation delegate:(id<CDVScreenOrientationDelegate>)orientationDelegate device:(CDV_iOSDevice)device
  138. {
  139. // Use UILaunchImageFile if specified in plist. Otherwise, use Default.
  140. NSString* imageName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UILaunchImageFile"];
  141. NSUInteger supportedOrientations = [orientationDelegate supportedInterfaceOrientations];
  142. // Checks to see if the developer has locked the orientation to use only one of Portrait or Landscape
  143. BOOL supportsLandscape = (supportedOrientations & UIInterfaceOrientationMaskLandscape);
  144. BOOL supportsPortrait = (supportedOrientations & UIInterfaceOrientationMaskPortrait || supportedOrientations & UIInterfaceOrientationMaskPortraitUpsideDown);
  145. // this means there are no mixed orientations in there
  146. BOOL isOrientationLocked = !(supportsPortrait && supportsLandscape);
  147. if (imageName)
  148. {
  149. imageName = [imageName stringByDeletingPathExtension];
  150. }
  151. else
  152. {
  153. imageName = @"Default";
  154. }
  155. // Add Asset Catalog specific prefixes
  156. if ([imageName isEqualToString:@"LaunchImage"])
  157. {
  158. if (device.iPhone4 || device.iPhone5 || device.iPad) {
  159. imageName = [imageName stringByAppendingString:@"-700"];
  160. } else if(device.iPhone6) {
  161. imageName = [imageName stringByAppendingString:@"-800"];
  162. } else if(device.iPhone6Plus) {
  163. imageName = [imageName stringByAppendingString:@"-800"];
  164. if (currentOrientation == UIInterfaceOrientationPortrait || currentOrientation == UIInterfaceOrientationPortraitUpsideDown)
  165. {
  166. imageName = [imageName stringByAppendingString:@"-Portrait"];
  167. }
  168. }
  169. }
  170. if (device.iPhone5)
  171. { // does not support landscape
  172. imageName = [imageName stringByAppendingString:@"-568h"];
  173. }
  174. else if (device.iPhone6)
  175. { // does not support landscape
  176. imageName = [imageName stringByAppendingString:@"-667h"];
  177. }
  178. else if (device.iPhone6Plus)
  179. { // supports landscape
  180. if (isOrientationLocked)
  181. {
  182. imageName = [imageName stringByAppendingString:(supportsLandscape ? @"-Landscape" : @"")];
  183. }
  184. else
  185. {
  186. switch (currentOrientation)
  187. {
  188. case UIInterfaceOrientationLandscapeLeft:
  189. case UIInterfaceOrientationLandscapeRight:
  190. imageName = [imageName stringByAppendingString:@"-Landscape"];
  191. break;
  192. default:
  193. break;
  194. }
  195. }
  196. imageName = [imageName stringByAppendingString:@"-736h"];
  197. }
  198. else if (device.iPad)
  199. { // supports landscape
  200. if (isOrientationLocked)
  201. {
  202. imageName = [imageName stringByAppendingString:(supportsLandscape ? @"-Landscape" : @"-Portrait")];
  203. }
  204. else
  205. {
  206. switch (currentOrientation)
  207. {
  208. case UIInterfaceOrientationLandscapeLeft:
  209. case UIInterfaceOrientationLandscapeRight:
  210. imageName = [imageName stringByAppendingString:@"-Landscape"];
  211. break;
  212. case UIInterfaceOrientationPortrait:
  213. case UIInterfaceOrientationPortraitUpsideDown:
  214. default:
  215. imageName = [imageName stringByAppendingString:@"-Portrait"];
  216. break;
  217. }
  218. }
  219. }
  220. return imageName;
  221. }
  222. - (UIInterfaceOrientation)getCurrentOrientation
  223. {
  224. UIInterfaceOrientation iOrientation = [UIApplication sharedApplication].statusBarOrientation;
  225. UIDeviceOrientation dOrientation = [UIDevice currentDevice].orientation;
  226. bool landscape;
  227. if (dOrientation == UIDeviceOrientationUnknown || dOrientation == UIDeviceOrientationFaceUp || dOrientation == UIDeviceOrientationFaceDown) {
  228. // If the device is laying down, use the UIInterfaceOrientation based on the status bar.
  229. landscape = UIInterfaceOrientationIsLandscape(iOrientation);
  230. } else {
  231. // If the device is not laying down, use UIDeviceOrientation.
  232. landscape = UIDeviceOrientationIsLandscape(dOrientation);
  233. // There's a bug in iOS!!!! http://openradar.appspot.com/7216046
  234. // So values needs to be reversed for landscape!
  235. if (dOrientation == UIDeviceOrientationLandscapeLeft)
  236. {
  237. iOrientation = UIInterfaceOrientationLandscapeRight;
  238. }
  239. else if (dOrientation == UIDeviceOrientationLandscapeRight)
  240. {
  241. iOrientation = UIInterfaceOrientationLandscapeLeft;
  242. }
  243. else if (dOrientation == UIDeviceOrientationPortrait)
  244. {
  245. iOrientation = UIInterfaceOrientationPortrait;
  246. }
  247. else if (dOrientation == UIDeviceOrientationPortraitUpsideDown)
  248. {
  249. iOrientation = UIInterfaceOrientationPortraitUpsideDown;
  250. }
  251. }
  252. return iOrientation;
  253. }
  254. // Sets the view's frame and image.
  255. - (void)updateImage
  256. {
  257. NSString* imageName = [self getImageName:[self getCurrentOrientation] delegate:(id<CDVScreenOrientationDelegate>)self.viewController device:[self getCurrentDevice]];
  258. if (![imageName isEqualToString:_curImageName])
  259. {
  260. UIImage* img = [UIImage imageNamed:imageName];
  261. _imageView.image = img;
  262. _curImageName = imageName;
  263. }
  264. // Check that splash screen's image exists before updating bounds
  265. if (_imageView.image)
  266. {
  267. [self updateBounds];
  268. }
  269. else
  270. {
  271. NSLog(@"WARNING: The splashscreen image named %@ was not found", imageName);
  272. }
  273. }
  274. - (void)updateBounds
  275. {
  276. UIImage* img = _imageView.image;
  277. CGRect imgBounds = (img) ? CGRectMake(0, 0, img.size.width, img.size.height) : CGRectZero;
  278. CGSize screenSize = [self.viewController.view convertRect:[UIScreen mainScreen].bounds fromView:nil].size;
  279. UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
  280. CGAffineTransform imgTransform = CGAffineTransformIdentity;
  281. /* If and only if an iPhone application is landscape-only as per
  282. * UISupportedInterfaceOrientations, the view controller's orientation is
  283. * landscape. In this case the image must be rotated in order to appear
  284. * correctly.
  285. */
  286. CDV_iOSDevice device = [self getCurrentDevice];
  287. if (UIInterfaceOrientationIsLandscape(orientation) && !device.iPhone6Plus && !device.iPad)
  288. {
  289. imgTransform = CGAffineTransformMakeRotation(M_PI / 2);
  290. imgBounds.size = CGSizeMake(imgBounds.size.height, imgBounds.size.width);
  291. }
  292. // There's a special case when the image is the size of the screen.
  293. if (CGSizeEqualToSize(screenSize, imgBounds.size))
  294. {
  295. CGRect statusFrame = [self.viewController.view convertRect:[UIApplication sharedApplication].statusBarFrame fromView:nil];
  296. if (!(IsAtLeastiOSVersion(@"7.0")))
  297. {
  298. imgBounds.origin.y -= statusFrame.size.height;
  299. }
  300. }
  301. else if (imgBounds.size.width > 0)
  302. {
  303. CGRect viewBounds = self.viewController.view.bounds;
  304. CGFloat imgAspect = imgBounds.size.width / imgBounds.size.height;
  305. CGFloat viewAspect = viewBounds.size.width / viewBounds.size.height;
  306. // This matches the behaviour of the native splash screen.
  307. CGFloat ratio;
  308. if (viewAspect > imgAspect)
  309. {
  310. ratio = viewBounds.size.width / imgBounds.size.width;
  311. }
  312. else
  313. {
  314. ratio = viewBounds.size.height / imgBounds.size.height;
  315. }
  316. imgBounds.size.height *= ratio;
  317. imgBounds.size.width *= ratio;
  318. }
  319. _imageView.transform = imgTransform;
  320. _imageView.frame = imgBounds;
  321. }
  322. - (void)setVisible:(BOOL)visible
  323. {
  324. if (visible != _visible)
  325. {
  326. _visible = visible;
  327. id fadeSplashScreenValue = [self.commandDelegate.settings objectForKey:[@"FadeSplashScreen" lowercaseString]];
  328. id fadeSplashScreenDuration = [self.commandDelegate.settings objectForKey:[@"FadeSplashScreenDuration" lowercaseString]];
  329. float fadeDuration = fadeSplashScreenDuration == nil ? kSplashScreenDurationDefault : [fadeSplashScreenDuration floatValue];
  330. id splashDurationString = [self.commandDelegate.settings objectForKey: [@"SplashScreenDelay" lowercaseString]];
  331. float splashDuration = splashDurationString == nil ? kSplashScreenDurationDefault : [splashDurationString floatValue];
  332. id autoHideSplashScreenValue = [self.commandDelegate.settings objectForKey:[@"AutoHideSplashScreen" lowercaseString]];
  333. BOOL autoHideSplashScreen = true;
  334. if (autoHideSplashScreenValue != nil) {
  335. autoHideSplashScreen = [autoHideSplashScreenValue boolValue];
  336. }
  337. if (!autoHideSplashScreen) {
  338. // CB-10412 SplashScreenDelay does not make sense if the splashscreen is hidden manually
  339. splashDuration = 0;
  340. }
  341. if (fadeSplashScreenValue == nil)
  342. {
  343. fadeSplashScreenValue = @"true";
  344. }
  345. if (![fadeSplashScreenValue boolValue])
  346. {
  347. fadeDuration = 0;
  348. }
  349. else if (fadeDuration < 30)
  350. {
  351. // [CB-9750] This value used to be in decimal seconds, so we will assume that if someone specifies 10
  352. // they mean 10 seconds, and not the meaningless 10ms
  353. fadeDuration *= 1000;
  354. }
  355. if (_visible)
  356. {
  357. if (_imageView == nil)
  358. {
  359. [self createViews];
  360. }
  361. }
  362. else if (fadeDuration == 0 && splashDuration == 0)
  363. {
  364. [self destroyViews];
  365. }
  366. else
  367. {
  368. __weak __typeof(self) weakSelf = self;
  369. float effectiveSplashDuration;
  370. if (!autoHideSplashScreen) {
  371. effectiveSplashDuration = (fadeDuration) / 1000;
  372. } else {
  373. effectiveSplashDuration = (splashDuration - fadeDuration) / 1000;
  374. }
  375. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (uint64_t) effectiveSplashDuration * NSEC_PER_SEC), dispatch_get_main_queue(), CFBridgingRelease(CFBridgingRetain(^(void) {
  376. [UIView transitionWithView:self.viewController.view
  377. duration:(fadeDuration / 1000)
  378. options:UIViewAnimationOptionTransitionNone
  379. animations:^(void) {
  380. [weakSelf hideViews];
  381. }
  382. completion:^(BOOL finished) {
  383. if (finished) {
  384. [weakSelf destroyViews];
  385. // TODO: It might also be nice to have a js event happen here -jm
  386. }
  387. }
  388. ];
  389. })));
  390. }
  391. }
  392. }
  393. @end