diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index eb09f99..8e70739 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -944,7 +944,7 @@ PODS: - React-Mapbuffer (0.73.0): - glog - React-debug - - react-native-improved (0.2.7): + - react-native-improved (0.2.8): - glog - RCT-Folly (= 2022.05.16.00) - React-Core @@ -1351,7 +1351,7 @@ SPEC CHECKSUMS: React-jsinspector: 9f6fb9ed9f03a0fb961ab8dc2e0e0ee0dc729e77 React-logger: 008caec0d6a587abc1e71be21bfac5ba1662fe6a React-Mapbuffer: 58fe558faf52ecde6705376700f848d0293d1cef - react-native-improved: 82e8e1912f5858a2ef60e56bb79ecba011fff0b2 + react-native-improved: a79262806efea7f6fe5d51f1879f7faa730edaca React-nativeconfig: a063483672b8add47a4875b0281e202908ff6747 React-NativeModulesApple: 169506a5fd708ab22811f76ee06a976595c367a1 React-perflogger: b61e5db8e5167f5e70366e820766c492847c082e diff --git a/ios/Views/RCTModalHostViewControllerImproved.h b/ios/Views/RCTModalHostViewControllerImproved.h new file mode 100644 index 0000000..7b4de29 --- /dev/null +++ b/ios/Views/RCTModalHostViewControllerImproved.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import +#import "RCTModalHostViewController.h" +#import "RCTModalHostViewImproved.h" + +@interface RCTModalHostViewControllerImproved : RCTModalHostViewController + +@end diff --git a/ios/Views/RCTModalHostViewControllerImproved.m b/ios/Views/RCTModalHostViewControllerImproved.m new file mode 100644 index 0000000..745cd8b --- /dev/null +++ b/ios/Views/RCTModalHostViewControllerImproved.m @@ -0,0 +1,35 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTModalHostViewControllerImproved.h" + +#import "RCTLog.h" +#import "RCTModalHostView.h" + +@implementation RCTModalHostViewControllerImproved { + CGRect _lastViewFrame; + UIStatusBarStyle _preferredStatusBarStyle; + BOOL _preferredStatusBarHidden; +} + +- (instancetype)init +{ + if (!(self = [super init])) { + return nil; + } + + self.modalInPresentation = YES; + + // _preferredStatusBarStyle = [RCTSharedApplication() statusBarStyle]; + // _preferredStatusBarHidden = [RCTSharedApplication() isStatusBarHidden]; + + return self; +} + + +@end + diff --git a/ios/Views/RCTModalHostViewImproved.h b/ios/Views/RCTModalHostViewImproved.h index 48fce62..59d5f88 100644 --- a/ios/Views/RCTModalHostViewImproved.h +++ b/ios/Views/RCTModalHostViewImproved.h @@ -7,6 +7,8 @@ #import "RCTModalHostView.h" #import "RCTModalHostViewImproved.h" +#import "RCTModalHostViewControllerImproved.h" +#import "RCTModalHostViewController.h" NS_ASSUME_NONNULL_BEGIN @@ -15,17 +17,23 @@ NS_ASSUME_NONNULL_BEGIN @interface RCTModalHostViewImproved : RCTModalHostView @property (nonatomic, weak) id delegate; +@property (nonatomic, strong) UIWindow *modalWindow; + +- (void)dismissModalViewControllerWithCompletion:(void (^)(void))completion; @end @protocol RCTModalHostViewInteractorImproved -- (void)presentModalHostView:(RCTModalHostViewImproved *)modalHostView +- (void)presentModalHostView:(RCTModalHostView *)modalHostView withViewController:(RCTModalHostViewController *)viewController animated:(BOOL)animated; - (void)dismissModalHostView:(RCTModalHostViewImproved *)modalHostView withViewController:(RCTModalHostViewController *)viewController animated:(BOOL)animated; +- (void)dismissModalHostViewWithCompletion:(RCTModalHostViewImproved *)modalHostView + withViewController:(RCTModalHostViewController *)viewController + animated:(BOOL)animated completion: (void (^)(void))completion; @end diff --git a/ios/Views/RCTModalHostViewImproved.m b/ios/Views/RCTModalHostViewImproved.m new file mode 100644 index 0000000..03d5deb --- /dev/null +++ b/ios/Views/RCTModalHostViewImproved.m @@ -0,0 +1,117 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import "RCTAssert.h" +#import "RCTBridge.h" +#import "RCTModalHostViewControllerImproved.h" +#import "RCTModalHostView.h" +#import "RCTTouchHandler.h" +#import "RCTUIManager.h" +#import "RCTUtils.h" +#import "UIView+React.h" + +@implementation RCTModalHostViewImproved { + __weak RCTBridge *_bridge; + BOOL _isPresented; + RCTModalHostViewController *_modalViewController; + RCTTouchHandler *_touchHandler; + UIView *_reactSubview; + UIInterfaceOrientation _lastKnownOrientation; + RCTDirectEventBlock _onRequestClose; +} + +RCT_NOT_IMPLEMENTED(-(instancetype)initWithFrame : (CGRect)frame) +RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : coder) + +- (instancetype)initWithBridge:(RCTBridge *)bridge +{ + self = [super initWithBridge:bridge]; + _modalViewController = [RCTModalHostViewController new]; + UIView *containerView = [UIView new]; + containerView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; + _modalViewController.view = containerView; + _touchHandler = [[RCTTouchHandler alloc] initWithBridge:bridge]; + _isPresented = NO; + + return self; +} + +- (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex +{ + [super insertReactSubview:subview atIndex:atIndex]; + [_modalViewController.view insertSubview:subview atIndex:0]; +} + +- (void)ensurePresentedOnlyIfNeeded +{ + BOOL shouldBePresented = !_isPresented && super.visible && self.window; + if (shouldBePresented) { + RCTAssert(self.reactViewController, @"Can't present modal view controller without a presenting view controller"); + _modalViewController.supportedInterfaceOrientations = [self supportedOrientationsMask]; + + if ([self.animationType isEqualToString:@"fade"]) { + _modalViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; + } else if ([self.animationType isEqualToString:@"slide"]) { + _modalViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical; + } + if (self.presentationStyle != UIModalPresentationNone) { + _modalViewController.modalPresentationStyle = self.presentationStyle; + } + _modalViewController.presentationController.delegate = self; + [self.delegate presentModalHostView:self withViewController:_modalViewController animated:[self hasAnimationType]]; + _isPresented = YES; + } + + BOOL shouldBeHidden = _isPresented && (!super.visible || !self.superview); + if (shouldBeHidden) { + [self dismissModalViewController]; + } +} + +- (UIInterfaceOrientationMask)supportedOrientationsMask +{ + if (self.supportedOrientations.count == 0) { + if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) { + return UIInterfaceOrientationMaskAll; + } else { + return UIInterfaceOrientationMaskPortrait; + } + } + + UIInterfaceOrientationMask supportedOrientations = 0; + for (NSString *orientation in self.supportedOrientations) { + if ([orientation isEqualToString:@"portrait"]) { + supportedOrientations |= UIInterfaceOrientationMaskPortrait; + } else if ([orientation isEqualToString:@"portrait-upside-down"]) { + supportedOrientations |= UIInterfaceOrientationMaskPortraitUpsideDown; + } else if ([orientation isEqualToString:@"landscape"]) { + supportedOrientations |= UIInterfaceOrientationMaskLandscape; + } else if ([orientation isEqualToString:@"landscape-left"]) { + supportedOrientations |= UIInterfaceOrientationMaskLandscapeLeft; + } else if ([orientation isEqualToString:@"landscape-right"]) { + supportedOrientations |= UIInterfaceOrientationMaskLandscapeRight; + } + } + return supportedOrientations; +} + +- (void)dismissModalViewController +{ + if (_isPresented) { + [self.delegate dismissModalHostView:self withViewController:_modalViewController animated:[self hasAnimationType]]; + _isPresented = NO; + } +} + +- (BOOL)hasAnimationType +{ + return ![self.animationType isEqualToString:@"none"]; +} + +@end diff --git a/ios/Views/RCTModalHostViewImproved.mm b/ios/Views/RCTModalHostViewImproved.mm deleted file mode 100644 index 96d3d21..0000000 --- a/ios/Views/RCTModalHostViewImproved.mm +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#import "RCTModalHostViewImproved.h" - -#import - -#import "RCTAssert.h" -#import "RCTBridge.h" -#import "RCTModalHostViewController.h" -#import "RCTTouchHandler.h" -#import "RCTUIManager.h" -#import "RCTUtils.h" -#import "UIView+React.h" - -@implementation RCTModalHostViewImproved { - __weak RCTBridge *_bridge; - BOOL _isPresented; - RCTModalHostViewController *_modalViewController; - RCTTouchHandler *_touchHandler; - UIView *_reactSubview; - UIInterfaceOrientation _lastKnownOrientation; - RCTDirectEventBlock _onRequestClose; -} - -RCT_NOT_IMPLEMENTED(-(instancetype)initWithFrame : (CGRect)frame) -RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : coder) - -- (instancetype)initWithBridge:(RCTBridge *)bridge -{ - NSLog(@"RCTModalHostViewImproved init"); - self = [super initWithBridge:bridge]; - - return self; -} - -@end diff --git a/ios/Views/RCTModalHostViewImprovedManager.m b/ios/Views/RCTModalHostViewImprovedManager.m new file mode 100644 index 0000000..a3d4af8 --- /dev/null +++ b/ios/Views/RCTModalHostViewImprovedManager.m @@ -0,0 +1,85 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +#import "RCTModalHostViewImprovedManager.h" +#import "RCTModalHostViewControllerImproved.h" +#import "RCTModalHostViewImproved.h" +#import "RCTShadowView.h" +#import "RCTModalManager.h" +#import "RCTModalHostViewManager.h" + +@interface RCTModalHostViewImprovedManager () + +@end + +@implementation RCTModalHostViewImprovedManager { + NSPointerArray *_hostViews; +} + +RCT_EXPORT_MODULE() + +- (UIView *)view +{ + [super view]; + RCTModalHostViewImproved *view = [[RCTModalHostViewImproved alloc] initWithBridge:self.bridge]; + view.delegate = self; + if (!_hostViews) { + _hostViews = [NSPointerArray weakObjectsPointerArray]; + } + [_hostViews addPointer:(__bridge void *)view]; + return view; +} + +- (void)presentModalHostView:(RCTModalHostViewImproved *)modalHostView + withViewController:(RCTModalHostViewControllerImproved *)viewController + animated:(BOOL)animated +{ + dispatch_block_t completionBlock = ^{ + if (modalHostView.onShow) { + modalHostView.onShow(nil); + } + }; + + dispatch_async(dispatch_get_main_queue(), ^{ + if (self.presentationBlock) { + self.presentationBlock([modalHostView reactViewController], viewController, animated, completionBlock); + } else { + [[modalHostView reactViewController] presentViewController:viewController + animated:animated + completion:completionBlock]; + } + }); +} + +- (void)dismissModalHostView:(RCTModalHostViewImproved *)modalHostView + withViewController:(RCTModalHostViewControllerImproved *)viewController + animated:(BOOL)animated +{ + dispatch_block_t completionBlock = ^{ + if (modalHostView.identifier) { + [[self.bridge moduleForClass:[RCTModalManager class]] modalDismissed:modalHostView.identifier]; + } + }; + + dispatch_async(dispatch_get_main_queue(), ^{ + if (self.dismissalBlock) { + self.dismissalBlock([modalHostView reactViewController], viewController, animated, completionBlock); + } else { + [viewController.presentingViewController dismissViewControllerAnimated:animated completion:completionBlock]; + } + }); +} + +- (void)invalidate +{ + for (RCTModalHostView *hostView in _hostViews) { + [hostView invalidate]; + } + _hostViews = nil; +} + +@end diff --git a/ios/Views/RCTModalHostViewImprovedManager.mm b/ios/Views/RCTModalHostViewImprovedManager.mm deleted file mode 100644 index 4b210b1..0000000 --- a/ios/Views/RCTModalHostViewImprovedManager.mm +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. -* -* This source code is licensed under the MIT license found in the -* LICENSE file in the root directory of this source tree. -*/ - -#import "RCTModalHostViewImprovedManager.h" -#import "RCTModalHostViewImproved.h" -#import "RCTShadowView.h" - -@interface RCTModalHostShadowView : RCTShadowView - -@end - -@interface RCTModalHostViewImprovedManager () - -@end - -@implementation RCTModalHostViewImprovedManager { - NSPointerArray *_hostViews; -} - -RCT_EXPORT_MODULE() - -- (UIView *)view -{ - [super view]; - RCTModalHostViewImproved *view = [[RCTModalHostViewImproved alloc] initWithBridge:self.bridge]; - view.delegate = self; - if (!_hostViews) { - _hostViews = [NSPointerArray weakObjectsPointerArray]; - } - [_hostViews addPointer:(__bridge void *)view]; - return view; -} - -/* Over-ride this method to add custom shadow view -- (RCTShadowView *)shadowView -{ - return [RCTModalHostShadowView new]; -} -*/ - -@end