react-native-navigation的迁移库

RNNCommandsHandler.m 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. #import "RNNCommandsHandler.h"
  2. #import "RNNNavigationOptions.h"
  3. #import "RNNRootViewController.h"
  4. #import "RNNSplitViewController.h"
  5. #import "RNNElementFinder.h"
  6. #import "React/RCTUIManager.h"
  7. #import "RNNErrorHandler.h"
  8. #import "RNNDefaultOptionsHelper.h"
  9. #import "UIViewController+RNNOptions.h"
  10. static NSString* const setRoot = @"setRoot";
  11. static NSString* const setStackRoot = @"setStackRoot";
  12. static NSString* const push = @"push";
  13. static NSString* const preview = @"preview";
  14. static NSString* const pop = @"pop";
  15. static NSString* const popTo = @"popTo";
  16. static NSString* const popToRoot = @"popToRoot";
  17. static NSString* const showModal = @"showModal";
  18. static NSString* const dismissModal = @"dismissModal";
  19. static NSString* const dismissAllModals = @"dismissAllModals";
  20. static NSString* const showOverlay = @"showOverlay";
  21. static NSString* const dismissOverlay = @"dismissOverlay";
  22. static NSString* const mergeOptions = @"mergeOptions";
  23. static NSString* const setDefaultOptions = @"setDefaultOptions";
  24. @interface RNNCommandsHandler() <RNNModalManagerDelegate>
  25. @end
  26. @implementation RNNCommandsHandler {
  27. RNNControllerFactory *_controllerFactory;
  28. RNNStore *_store;
  29. RNNModalManager* _modalManager;
  30. RNNOverlayManager* _overlayManager;
  31. RNNNavigationStackManager* _stackManager;
  32. RNNEventEmitter* _eventEmitter;
  33. UIApplication* _sharedApplication;
  34. UIWindow* _mainWindow;
  35. }
  36. - (instancetype)initWithStore:(RNNStore*)store controllerFactory:(RNNControllerFactory*)controllerFactory eventEmitter:(RNNEventEmitter *)eventEmitter stackManager:(RNNNavigationStackManager *)stackManager modalManager:(RNNModalManager *)modalManager overlayManager:(RNNOverlayManager *)overlayManager sharedApplication:(UIApplication *)sharedApplication {
  37. self = [super init];
  38. _store = store;
  39. _controllerFactory = controllerFactory;
  40. _eventEmitter = eventEmitter;
  41. _modalManager = modalManager;
  42. _modalManager.delegate = self;
  43. _stackManager = stackManager;
  44. _overlayManager = overlayManager;
  45. _sharedApplication = sharedApplication;
  46. return self;
  47. }
  48. #pragma mark - public
  49. - (void)setRoot:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion {
  50. [self assertReady];
  51. if (!_mainWindow) {
  52. _mainWindow = _sharedApplication.keyWindow;
  53. }
  54. [_modalManager dismissAllModalsAnimated:NO];
  55. [_store removeAllComponentsFromWindow:_mainWindow];
  56. UIViewController *vc = [_controllerFactory createLayout:layout[@"root"] saveToStore:_store];
  57. _mainWindow.rootViewController = vc;
  58. [_eventEmitter sendOnNavigationCommandCompletion:setRoot params:@{@"layout": layout}];
  59. completion();
  60. }
  61. - (void)mergeOptions:(NSString*)componentId options:(NSDictionary*)mergeOptions completion:(RNNTransitionCompletionBlock)completion {
  62. [self assertReady];
  63. UIViewController<RNNLayoutProtocol>* vc = (UIViewController<RNNLayoutProtocol>*)[_store findComponentForId:componentId];
  64. RNNNavigationOptions* newOptions = [[RNNNavigationOptions alloc] initWithDict:mergeOptions];
  65. if ([vc conformsToProtocol:@protocol(RNNLayoutProtocol)] || [vc isKindOfClass:[RNNRootViewController class]]) {
  66. [CATransaction begin];
  67. [CATransaction setCompletionBlock:completion];
  68. [vc overrideOptions:newOptions];
  69. [vc mergeOptions:newOptions];
  70. [CATransaction commit];
  71. }
  72. }
  73. - (void)setDefaultOptions:(NSDictionary*)optionsDict completion:(RNNTransitionCompletionBlock)completion {
  74. [self assertReady];
  75. RNNNavigationOptions* defaultOptions = [[RNNNavigationOptions alloc] initWithDict:optionsDict];
  76. [_controllerFactory setDefaultOptions:defaultOptions];
  77. UIViewController *rootViewController = UIApplication.sharedApplication.delegate.window.rootViewController;
  78. [RNNDefaultOptionsHelper recrusivelySetDefaultOptions:defaultOptions onRootViewController:rootViewController];
  79. completion();
  80. }
  81. - (void)push:(NSString*)componentId layout:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection {
  82. [self assertReady];
  83. UIViewController<RNNLayoutProtocol> *newVc = [_controllerFactory createLayout:layout saveToStore:_store];
  84. UIViewController *fromVC = [_store findComponentForId:componentId];
  85. if ([[newVc.resolveOptions.preview.reactTag getWithDefaultValue:@(0)] floatValue] > 0) {
  86. UIViewController* vc = [_store findComponentForId:componentId];
  87. if([vc isKindOfClass:[RNNRootViewController class]]) {
  88. RNNRootViewController* rootVc = (RNNRootViewController*)vc;
  89. rootVc.previewController = newVc;
  90. rootVc.previewCallback = ^(UIViewController *vcc) {
  91. RNNRootViewController* rvc = (RNNRootViewController*)vcc;
  92. [self->_eventEmitter sendOnPreviewCompleted:componentId previewComponentId:newVc.layoutInfo.componentId];
  93. if ([newVc.resolveOptions.preview.commit getWithDefaultValue:NO]) {
  94. [CATransaction begin];
  95. [CATransaction setCompletionBlock:^{
  96. [self->_eventEmitter sendOnNavigationCommandCompletion:push params:@{@"componentId": componentId}];
  97. completion();
  98. }];
  99. [rvc.navigationController pushViewController:newVc animated:YES];
  100. [CATransaction commit];
  101. }
  102. };
  103. CGSize size = CGSizeMake(rootVc.view.frame.size.width, rootVc.view.frame.size.height);
  104. if (newVc.resolveOptions.preview.width.hasValue) {
  105. size.width = [newVc.resolveOptions.preview.width.get floatValue];
  106. }
  107. if (newVc.resolveOptions.preview.height.hasValue) {
  108. size.height = [newVc.resolveOptions.preview.height.get floatValue];
  109. }
  110. if (newVc.resolveOptions.preview.width.hasValue || newVc.resolveOptions.preview.height.hasValue) {
  111. newVc.preferredContentSize = size;
  112. }
  113. RCTExecuteOnMainQueue(^{
  114. UIView *view = [[ReactNativeNavigation getBridge].uiManager viewForReactTag:newVc.resolveOptions.preview.reactTag.get];
  115. [rootVc registerForPreviewingWithDelegate:(id)rootVc sourceView:view];
  116. });
  117. }
  118. } else {
  119. id animationDelegate = (newVc.resolveOptions.animations.push.hasCustomAnimation || newVc.getCurrentLeaf.isCustomTransitioned) ? newVc : nil;
  120. [newVc.getCurrentLeaf waitForReactViewRender:(newVc.resolveOptions.animations.push.waitForRender || animationDelegate) perform:^{
  121. [_stackManager push:newVc onTop:fromVC animated:newVc.resolveOptions.animations.push.enable animationDelegate:animationDelegate completion:^{
  122. [_eventEmitter sendOnNavigationCommandCompletion:push params:@{@"componentId": componentId}];
  123. completion();
  124. } rejection:rejection];
  125. }];
  126. }
  127. }
  128. - (void)setStackRoot:(NSString*)componentId layout:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection {
  129. [self assertReady];
  130. UIViewController<RNNParentProtocol> *newVC = [_controllerFactory createLayout:layout saveToStore:_store];
  131. RNNNavigationOptions* options = [newVC getCurrentChild].resolveOptions;
  132. UIViewController *fromVC = [_store findComponentForId:componentId];
  133. __weak typeof(RNNEventEmitter*) weakEventEmitter = _eventEmitter;
  134. [_stackManager setStackRoot:newVC fromViewController:fromVC animated:options.animations.setStackRoot.enable completion:^{
  135. [weakEventEmitter sendOnNavigationCommandCompletion:setStackRoot params:@{@"componentId": componentId}];
  136. completion();
  137. } rejection:rejection];
  138. }
  139. - (void)pop:(NSString*)componentId mergeOptions:(NSDictionary*)mergeOptions completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection {
  140. [self assertReady];
  141. RNNRootViewController *vc = (RNNRootViewController*)[_store findComponentForId:componentId];
  142. RNNNavigationOptions *options = [[RNNNavigationOptions alloc] initWithDict:mergeOptions];
  143. [vc overrideOptions:options];
  144. UINavigationController *nvc = vc.navigationController;
  145. if ([nvc topViewController] == vc) {
  146. if (vc.resolveOptions.animations.pop) {
  147. nvc.delegate = vc;
  148. } else {
  149. nvc.delegate = nil;
  150. }
  151. } else {
  152. NSMutableArray * vcs = nvc.viewControllers.mutableCopy;
  153. [vcs removeObject:vc];
  154. [nvc setViewControllers:vcs animated:vc.resolveOptions.animations.pop.enable];
  155. }
  156. [_stackManager pop:vc animated:vc.resolveOptions.animations.pop.enable completion:^{
  157. [_store removeComponent:componentId];
  158. [_eventEmitter sendOnNavigationCommandCompletion:pop params:@{@"componentId": componentId}];
  159. completion();
  160. } rejection:rejection];
  161. }
  162. - (void)popTo:(NSString*)componentId mergeOptions:(NSDictionary *)mergeOptions completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection {
  163. [self assertReady];
  164. RNNRootViewController *vc = (RNNRootViewController*)[_store findComponentForId:componentId];
  165. RNNNavigationOptions *options = [[RNNNavigationOptions alloc] initWithDict:mergeOptions];
  166. [vc overrideOptions:options];
  167. [_stackManager popTo:vc animated:vc.resolveOptions.animations.pop.enable completion:^(NSArray *poppedViewControllers) {
  168. [_eventEmitter sendOnNavigationCommandCompletion:popTo params:@{@"componentId": componentId}];
  169. [self removePopedViewControllers:poppedViewControllers];
  170. completion();
  171. } rejection:rejection];
  172. }
  173. - (void)popToRoot:(NSString*)componentId mergeOptions:(NSDictionary *)mergeOptions completion:(RNNTransitionCompletionBlock)completion rejection:(RCTPromiseRejectBlock)rejection {
  174. [self assertReady];
  175. RNNRootViewController *vc = (RNNRootViewController*)[_store findComponentForId:componentId];
  176. RNNNavigationOptions *options = [[RNNNavigationOptions alloc] initWithDict:mergeOptions];
  177. [vc overrideOptions:options];
  178. [CATransaction begin];
  179. [CATransaction setCompletionBlock:^{
  180. [_eventEmitter sendOnNavigationCommandCompletion:popToRoot params:@{@"componentId": componentId}];
  181. completion();
  182. }];
  183. [_stackManager popToRoot:vc animated:vc.resolveOptions.animations.pop.enable completion:^(NSArray *poppedViewControllers) {
  184. [self removePopedViewControllers:poppedViewControllers];
  185. } rejection:^(NSString *code, NSString *message, NSError *error) {
  186. }];
  187. [CATransaction commit];
  188. }
  189. - (void)showModal:(NSDictionary*)layout completion:(RNNTransitionWithComponentIdCompletionBlock)completion {
  190. [self assertReady];
  191. UIViewController<RNNParentProtocol> *newVc = [_controllerFactory createLayout:layout saveToStore:_store];
  192. [newVc.getCurrentLeaf waitForReactViewRender:newVc.getCurrentLeaf.resolveOptions.animations.showModal.waitForRender perform:^{
  193. [_modalManager showModal:newVc animated:newVc.getCurrentChild.resolveOptions.animations.showModal.enable hasCustomAnimation:newVc.getCurrentChild.resolveOptions.animations.showModal.hasCustomAnimation completion:^(NSString *componentId) {
  194. [_eventEmitter sendOnNavigationCommandCompletion:showModal params:@{@"layout": layout}];
  195. completion(componentId);
  196. }];
  197. }];
  198. }
  199. - (void)dismissModal:(NSString*)componentId mergeOptions:(NSDictionary *)mergeOptions completion:(RNNTransitionCompletionBlock)completion rejection:(RNNTransitionRejectionBlock)reject {
  200. [self assertReady];
  201. UIViewController<RNNParentProtocol> *modalToDismiss = (UIViewController<RNNParentProtocol>*)[_store findComponentForId:componentId];
  202. if (!modalToDismiss.isModal) {
  203. [RNNErrorHandler reject:reject withErrorCode:1013 errorDescription:@"component is not a modal"];
  204. return;
  205. }
  206. RNNNavigationOptions *options = [[RNNNavigationOptions alloc] initWithDict:mergeOptions];
  207. [modalToDismiss.getCurrentChild overrideOptions:options];
  208. [self removePopedViewControllers:modalToDismiss.navigationController.viewControllers];
  209. [CATransaction begin];
  210. [CATransaction setCompletionBlock:^{
  211. [_eventEmitter sendOnNavigationCommandCompletion:dismissModal params:@{@"componentId": componentId}];
  212. }];
  213. [_modalManager dismissModal:modalToDismiss completion:completion];
  214. [CATransaction commit];
  215. }
  216. - (void)dismissAllModals:(NSDictionary *)mergeOptions completion:(RNNTransitionCompletionBlock)completion {
  217. [self assertReady];
  218. [CATransaction begin];
  219. [CATransaction setCompletionBlock:^{
  220. [_eventEmitter sendOnNavigationCommandCompletion:dismissAllModals params:@{}];
  221. completion();
  222. }];
  223. RNNNavigationOptions* options = [[RNNNavigationOptions alloc] initWithDict:mergeOptions];
  224. [_modalManager dismissAllModalsAnimated:options.animations.dismissModal.enable];
  225. [CATransaction commit];
  226. }
  227. - (void)showOverlay:(NSDictionary *)layout completion:(RNNTransitionCompletionBlock)completion {
  228. [self assertReady];
  229. UIViewController<RNNParentProtocol>* overlayVC = [_controllerFactory createLayout:layout saveToStore:_store];
  230. UIWindow* overlayWindow = [[RNNOverlayWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
  231. overlayWindow.rootViewController = overlayVC;
  232. [_overlayManager showOverlayWindow:overlayWindow];
  233. [_eventEmitter sendOnNavigationCommandCompletion:showOverlay params:@{@"layout": layout}];
  234. completion();
  235. }
  236. - (void)dismissOverlay:(NSString*)componentId completion:(RNNTransitionCompletionBlock)completion rejection:(RNNTransitionRejectionBlock)reject {
  237. [self assertReady];
  238. UIViewController* viewController = [_store findComponentForId:componentId];
  239. if (viewController) {
  240. [_overlayManager dismissOverlay:viewController];
  241. [_eventEmitter sendOnNavigationCommandCompletion:dismissOverlay params:@{@"componentId": componentId}];
  242. completion();
  243. } else {
  244. [RNNErrorHandler reject:reject withErrorCode:1010 errorDescription:@"ComponentId not found"];
  245. }
  246. }
  247. #pragma mark - private
  248. - (void)removePopedViewControllers:(NSArray*)viewControllers {
  249. for (UIViewController *popedVC in viewControllers) {
  250. [_store removeComponentByViewControllerInstance:popedVC];
  251. }
  252. }
  253. - (void)assertReady {
  254. if (!_store.isReadyToReceiveCommands) {
  255. [[NSException exceptionWithName:@"BridgeNotLoadedError"
  256. reason:@"Bridge not yet loaded! Send commands after Navigation.events().onAppLaunched() has been called."
  257. userInfo:nil]
  258. raise];
  259. }
  260. }
  261. #pragma mark - RNNModalManagerDelegate
  262. - (void)dismissedModal:(UIViewController<RNNParentProtocol> *)viewController {
  263. [_eventEmitter sendModalsDismissedEvent:viewController.layoutInfo.componentId numberOfModalsDismissed:@(1)];
  264. }
  265. - (void)dismissedMultipleModals:(NSArray *)viewControllers {
  266. if (viewControllers && viewControllers.count) {
  267. [_eventEmitter sendModalsDismissedEvent:((UIViewController<RNNParentProtocol> *)viewControllers.lastObject).layoutInfo.componentId numberOfModalsDismissed:@(viewControllers.count)];
  268. }
  269. }
  270. @end