Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/ios/RNNAnimator.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#import "RNNElementView.h"

@interface RNNAnimator : NSObject <UIViewControllerAnimatedTransitioning>

-(instancetype)initWithAnimationsDictionary:(NSDictionary *)animationsDic;
-(void)setupTransition:(NSDictionary*)data;

@end
11 changes: 11 additions & 0 deletions lib/ios/RNNAnimator.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,17 @@ @interface RNNAnimator()

@implementation RNNAnimator

- (instancetype)initWithAnimationsDictionary:(NSDictionary *)animationsDic {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can be easily unit-tested in native (XCtests). I'll merge the changes, plz open a separate issue on it and assign yourself

self = [super init];
if (animationsDic) {
[self setupTransition:animationsDic];
} else {
return nil;
}

return self;
}

-(void)setupTransition:(NSDictionary*)data{
if ([data objectForKey:@"animations"]) {
self.animations= [data objectForKey:@"animations"];
Expand Down
12 changes: 8 additions & 4 deletions lib/ios/RNNBridgeModule.m
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ -(instancetype)initWithCommandsHandler:(RNNCommandsHandler *)commandsHandler {
[_commandsHandler setOptions:containerId options:options];
}

RCT_EXPORT_METHOD(push:(NSString*)containerId layout:(NSDictionary*)layout) {
[_commandsHandler push:containerId layout:layout];
RCT_EXPORT_METHOD(push:(NSString*)containerId layout:(NSDictionary*)layout resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
[_commandsHandler push:containerId layout:layout completion:^(id result) {
resolve(result);
}];
}

RCT_EXPORT_METHOD(pop:(NSString*)containerId options:(NSDictionary*)options) {
Expand All @@ -42,8 +44,10 @@ -(instancetype)initWithCommandsHandler:(RNNCommandsHandler *)commandsHandler {
[_commandsHandler popToRoot:containerId];
}

RCT_EXPORT_METHOD(showModal:(NSDictionary*)layout) {
[_commandsHandler showModal:layout];
RCT_EXPORT_METHOD(showModal:(NSDictionary*)layout resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
[_commandsHandler showModal:layout completion:^(id containerID) {
resolve(containerID);
}];
}

RCT_EXPORT_METHOD(dismissModal:(NSString*)containerId) {
Expand Down
4 changes: 2 additions & 2 deletions lib/ios/RNNCommandsHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@

-(void) setOptions:(NSString*)containerId options:(NSDictionary*)options;

-(void) push:(NSString*)containerId layout:(NSDictionary*)layout;
-(void) push:(NSString*)containerId layout:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion;

-(void) pop:(NSString*)containerId options:(NSDictionary*)options;

-(void) popTo:(NSString*)containerId;

-(void) popToRoot:(NSString*)containerId;

-(void) showModal:(NSDictionary*)layout;
-(void) showModal:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion;

-(void) dismissModal:(NSString*)containerId;

Expand Down
21 changes: 7 additions & 14 deletions lib/ios/RNNCommandsHandler.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#import "RNNNavigationStackManager.h"
#import "RNNNavigationOptions.h"
#import "RNNRootViewController.h"
#import "React/RCTUIManager.h"

@implementation RNNCommandsHandler {
RNNControllerFactory *_controllerFactory;
Expand Down Expand Up @@ -47,20 +48,12 @@ -(void) setOptions:(NSString*)containerId options:(NSDictionary*)options {
}
}

-(void)push:(NSString*)containerId layout:(NSDictionary*)layout {
-(void) push:(NSString*)containerId layout:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion {
[self assertReady];
NSDictionary* customAnimation = layout[@"data"][@"customTransition"];
UIViewController *newVc = [_controllerFactory createLayoutAndSaveToStore:layout];
RCTBridge* bridge = _bridge;
if (customAnimation) {
if ([customAnimation objectForKey:@"animations"]) {
[_navigationStackManager push:newVc onTop:containerId customAnimationData:(NSDictionary*)customAnimation bridge:bridge];
} else {
[[NSException exceptionWithName:NSInvalidArgumentException reason:@"unsupported transitionAnimation" userInfo:nil] raise];
}
} else {
[_navigationStackManager push:newVc onTop:containerId customAnimationData:(NSDictionary*)nil bridge:bridge];
}
UIViewController *fromVc = [_store findContainerForId:containerId];
[_bridge.uiManager setAvailableSize:fromVc.view.bounds.size forRootView:newVc.view];
[_navigationStackManager push:newVc onTop:containerId completion:completion];
}

-(void)pop:(NSString*)containerId options:(NSDictionary*)options{
Expand Down Expand Up @@ -90,11 +83,11 @@ -(void) popToRoot:(NSString*)containerId {
[_navigationStackManager popToRoot:containerId];
}

-(void) showModal:(NSDictionary*)layout {
-(void) showModal:(NSDictionary*)layout completion:(RNNTransitionCompletionBlock)completion {
[self assertReady];

UIViewController *newVc = [_controllerFactory createLayoutAndSaveToStore:layout];
[_modalManager showModal:newVc];
[_modalManager showModal:newVc completion:completion];
}

-(void) dismissModal:(NSString*)containerId {
Expand Down
4 changes: 3 additions & 1 deletion lib/ios/RNNControllerFactory.m
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,11 @@ - (UIViewController*)fromTree:(NSDictionary*)json {

- (RNNRootViewController*)createContainer:(RNNLayoutNode*)node {
NSString* name = node.data[@"name"];
NSDictionary* customTransition = node.data[@"customTransition"];
RNNAnimator* animator = [[RNNAnimator alloc] initWithAnimationsDictionary:customTransition];
RNNNavigationOptions* options = [[RNNNavigationOptions alloc] initWithDict:node.data[@"navigationOptions"]];
NSString* containerId = node.nodeId;
return [[RNNRootViewController alloc] initWithName:name withOptions:options withContainerId:containerId rootViewCreator:_creator eventEmitter:_eventEmitter];
return [[RNNRootViewController alloc] initWithName:name withOptions:options withContainerId:containerId rootViewCreator:_creator eventEmitter:_eventEmitter animator:animator];
}

- (RNNNavigationController*)createContainerStack:(RNNLayoutNode*)node {
Expand Down
2 changes: 1 addition & 1 deletion lib/ios/RNNModalManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
@property (nonatomic, strong) UIViewController* toVC;

-(instancetype)initWithStore:(RNNStore*)store;
-(void)showModal:(UIViewController*)viewController;
-(void)showModal:(UIViewController*)viewController completion:(RNNTransitionCompletionBlock)completion;
-(void)dismissModal:(NSString*)containerId;
-(void)dismissAllModals;

Expand Down
15 changes: 8 additions & 7 deletions lib/ios/RNNModalManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

@implementation RNNModalManager {
RNNStore *_store;
RNNTransitionCompletionBlock _completionBlock;
}


Expand All @@ -21,16 +22,16 @@ -(void)waitForContentToAppearAndThen:(SEL)nameOfSelector {
-(void)showModalAfterLoad:(NSDictionary*)notif {
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"RCTContentDidAppearNotification" object:nil];
UIViewController *topVC = [self topPresentedVC];
[topVC presentViewController:self.toVC animated:YES completion:nil];
[topVC presentViewController:self.toVC animated:YES completion:^{
if (_completionBlock) {
_completionBlock([_store containerKeyForInstance:self.toVC]);
}
}];
}

//-(void)prepareShowModal{
//
//}

-(void)showModal:(UIViewController *)viewController {
-(void)showModal:(UIViewController *)viewController completion:(RNNTransitionCompletionBlock)completion {
self.toVC = viewController;
// [self prepareShowModal]
_completionBlock = completion;
[self waitForContentToAppearAndThen:@selector(showModalAfterLoad:)];
}

Expand Down
2 changes: 1 addition & 1 deletion lib/ios/RNNNavigationStackManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
-(instancetype)initWithStore:(RNNStore*)store;


-(void)push:(UIViewController*)newTop onTop:(NSString*)containerId customAnimationData:(NSDictionary*)customAnimationData bridge:(RCTBridge*)bridge;
-(void)push:(UIViewController*)newTop onTop:(NSString*)containerId completion:(RNNTransitionCompletionBlock)completion;
-(void)pop:(NSString*)containerId withAnimationData:(NSDictionary*)animationData;
-(void)popTo:(NSString*)containerId;
-(void)popToRoot:(NSString*)containerId;
Expand Down
35 changes: 20 additions & 15 deletions lib/ios/RNNNavigationStackManager.m
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#import "RNNNavigationStackManager.h"
#import "RNNRootViewController.h"
#import "React/RCTUIManager.h"
#import "RNNAnimator.h"


dispatch_queue_t RCTGetUIManagerQueue(void);
@implementation RNNNavigationStackManager {
RNNStore *_store;
RNNTransitionCompletionBlock _completionBlock;
}

-(instancetype)initWithStore:(RNNStore*)store {
Expand All @@ -15,30 +15,25 @@ -(instancetype)initWithStore:(RNNStore*)store {
return self;
}


-(void)push:(UIViewController *)newTop onTop:(NSString *)containerId customAnimationData:(NSDictionary*)customAnimationData bridge:(RCTBridge*)bridge {
-(void)push:(UIViewController *)newTop onTop:(NSString *)containerId completion:(RNNTransitionCompletionBlock)completion {
UIViewController *vc = [_store findContainerForId:containerId];
[self preparePush:newTop onTopVC:vc customAnimationData:customAnimationData bridge:bridge];
[self preparePush:newTop onTopVC:vc completion:completion];
[self waitForContentToAppearAndThen:@selector(pushAfterLoad:)];
}

-(void)preparePush:(UIViewController *)newTop onTopVC:(UIViewController*)vc customAnimationData:(NSDictionary*)customAnimationData bridge:(RCTBridge*)bridge {
if (customAnimationData) {
-(void)preparePush:(UIViewController *)newTop onTopVC:(UIViewController*)vc completion:(RNNTransitionCompletionBlock)completion {
self.toVC = (RNNRootViewController*)newTop;
self.fromVC = vc;

if (self.toVC.isAnimated) {
RNNRootViewController* newTopRootView = (RNNRootViewController*)newTop;
self.fromVC = vc;
self.toVC = newTopRootView;
vc.navigationController.delegate = newTopRootView;
[newTopRootView.animator setupTransition:customAnimationData];
RCTUIManager *uiManager = bridge.uiManager;
CGRect screenBound = [vc.view bounds];
CGSize screenSize = screenBound.size;
[uiManager setAvailableSize:screenSize forRootView:self.toVC.view];
} else {
self.fromVC = vc;
self.toVC = (RNNRootViewController*)newTop;
vc.navigationController.delegate = nil;
self.fromVC.navigationController.interactivePopGestureRecognizer.delegate = nil;
}

_completionBlock = completion;
}

-(void)waitForContentToAppearAndThen:(SEL)nameOfSelector {
Expand All @@ -50,7 +45,17 @@ -(void)waitForContentToAppearAndThen:(SEL)nameOfSelector {

-(void)pushAfterLoad:(NSDictionary*)notif {
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"RCTContentDidAppearNotification" object:nil];
[CATransaction begin];
[CATransaction setCompletionBlock:^{
if (_completionBlock) {
_completionBlock(self.toVC.containerId);
_completionBlock = nil;
}
}];

[[self.fromVC navigationController] pushViewController:self.toVC animated:YES];
[CATransaction commit];

self.toVC = nil;
self.fromVC.navigationController.interactivePopGestureRecognizer.delegate = nil;
self.fromVC = nil;
Expand Down
7 changes: 5 additions & 2 deletions lib/ios/RNNRootViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#import "RNNEventEmitter.h"
#import "RNNNavigationOptions.h"
#import "RNNAnimator.h"

@interface RNNRootViewController : UIViewController <UINavigationControllerDelegate>
@property (nonatomic, strong) RNNNavigationOptions* navigationOptions;
@property (nonatomic, strong) RNNAnimator* animator;
Expand All @@ -16,9 +17,11 @@
withOptions:(RNNNavigationOptions*)options
withContainerId:(NSString*)containerId
rootViewCreator:(id<RNNRootViewCreator>)creator
eventEmitter:(RNNEventEmitter*)eventEmitter;
eventEmitter:(RNNEventEmitter*)eventEmitter
animator:(RNNAnimator*)animator;


-(void) applyNavigationButtons;
-(void)applyNavigationButtons;
-(BOOL)isAnimated;

@end
9 changes: 7 additions & 2 deletions lib/ios/RNNRootViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,20 @@ -(instancetype)initWithName:(NSString*)name
withOptions:(RNNNavigationOptions*)options
withContainerId:(NSString*)containerId
rootViewCreator:(id<RNNRootViewCreator>)creator
eventEmitter:(RNNEventEmitter*)eventEmitter {
eventEmitter:(RNNEventEmitter*)eventEmitter
animator:(RNNAnimator *)animator {
self = [super init];
self.containerId = containerId;
self.containerName = name;
self.navigationOptions = options;
self.eventEmitter = eventEmitter;
self.animator = animator;
self.view = [creator createRootView:self.containerName rootViewId:self.containerId];

[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(onJsReload)
name:RCTJavaScriptWillStartLoadingNotification
object:nil];
self.animator = [[RNNAnimator alloc] init];
self.navigationController.modalPresentationStyle = UIModalPresentationCustom;
self.navigationController.delegate = self;
self.navigationButtons = [[RNNNavigationButtons alloc] initWithViewController:self];
Expand All @@ -46,6 +47,10 @@ - (void)viewDidLoad {
[super viewDidLoad];
}

-(BOOL)isAnimated {
return self.animator;
}

- (BOOL)prefersStatusBarHidden {
if ([self.navigationOptions.statusBarHidden boolValue]) {
return YES;
Expand Down
2 changes: 2 additions & 0 deletions lib/ios/RNNStore.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#import <UIKit/UIKit.h>
#import "RNNRootViewController.h"

typedef void (^RNNTransitionCompletionBlock)(id result);

@interface RNNStore : NSObject

-(UIViewController*) findContainerForId:(NSString*)containerId;
Expand Down
11 changes: 6 additions & 5 deletions lib/ios/ReactNativeNavigationTests/RNNCommandsHandlerTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ - (void)testAssertReadyForEachMethodThrowsExceptoins {
[self.store setReadyToReceiveCommands:false];
for (NSString* methodName in methods) {
SEL s = NSSelectorFromString(methodName);
NSMethodSignature* signature = [self.uut methodSignatureForSelector:s];
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature];
invocation.selector = s;
XCTAssertThrowsSpecificNamed([invocation invokeWithTarget:self.uut], NSException, @"BridgeNotLoadedError");
IMP imp = [self.uut methodForSelector:s];
void (*func)(id, SEL, id, id, id) = (void *)imp;

XCTAssertThrowsSpecificNamed(func(self.uut,s, nil, nil, nil), NSException, @"BridgeNotLoadedError");
}
}

Expand Down Expand Up @@ -70,7 +70,8 @@ -(void)testDynamicStylesMergeWithStaticStyles {
withOptions:initialOptions
withContainerId:@"containerId"
rootViewCreator:[[RNNTestRootViewCreator alloc] init]
eventEmitter:nil];
eventEmitter:nil
animator:nil];
RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:vc];
[vc viewWillAppear:false];
XCTAssertTrue([vc.navigationItem.title isEqual:@"the title"]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ - (void)setUp {
self.containerId = @"cntId";
self.emitter = nil;
self.options = [RNNNavigationOptions new];
self.uut = [[RNNRootViewController alloc] initWithName:self.pageName withOptions:self.options withContainerId:self.containerId rootViewCreator:self.creator eventEmitter:self.emitter];
self.uut = [[RNNRootViewController alloc] initWithName:self.pageName withOptions:self.options withContainerId:self.containerId rootViewCreator:self.creator eventEmitter:self.emitter animator:nil];
}

-(void)testTopBarBackgroundColor_validColor{
Expand Down
10 changes: 6 additions & 4 deletions lib/src/adapters/NativeCommandsSender.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ class NativeCommandsSender {
this.nativeCommandsModule.setOptions(containerId, options);
}

push(onContainerId, layout) {
return this.nativeCommandsModule.push(onContainerId, layout);
async push(onContainerId, layout) {
const pushedContainerId = await this.nativeCommandsModule.push(onContainerId, layout);
return pushedContainerId;
}

pop(containerId, options) {
Expand All @@ -33,8 +34,9 @@ class NativeCommandsSender {
return this.nativeCommandsModule.popToRoot(containerId);
}

showModal(layout) {
return this.nativeCommandsModule.showModal(layout);
async showModal(layout) {
const completed = await this.nativeCommandsModule.showModal(layout);
return completed;
}

dismissModal(containerId) {
Expand Down