UNPKG

5.37 kBPlain TextView Raw
1#import "RNSModule.h"
2#import <React/RCTBridge+Private.h>
3#import <React/RCTBridge.h>
4#import <React/RCTUIManager.h>
5#import <React/RCTUIManagerUtils.h>
6#import <React/RCTUtils.h>
7#include <jsi/jsi.h>
8#import "RNSScreenStack.h"
9#import "RNScreensTurboModule.h"
10
11NS_ASSUME_NONNULL_BEGIN
12
13@implementation RNSModule {
14 std::atomic<bool> isActiveTransition;
15}
16
17RCT_EXPORT_MODULE()
18
19#ifdef RCT_NEW_ARCH_ENABLED
20@synthesize viewRegistry_DEPRECATED = _viewRegistry_DEPRECATED;
21#endif // RCT_NEW_ARCH_ENABLED
22@synthesize bridge = _bridge;
23
24- (dispatch_queue_t)methodQueue
25{
26 // It seems that due to how UIBlocks work with uiManager, we need to call the methods there
27 // for the blocks to be dispatched before the batch is completed
28 return dispatch_get_main_queue();
29}
30
31- (NSDictionary *)constantsToExport
32{
33 [self installHostObject];
34 return @{};
35}
36
37+ (BOOL)requiresMainQueueSetup
38{
39 return NO;
40}
41
42- (RNSScreenStackView *)getScreenStackView:(NSNumber *)reactTag
43{
44 RCTAssertMainQueue();
45 RNSScreenStackView *view;
46#ifdef RCT_NEW_ARCH_ENABLED
47 view = (RNSScreenStackView *)[self.viewRegistry_DEPRECATED viewForReactTag:reactTag];
48#else
49 view = (RNSScreenStackView *)[self.bridge.uiManager viewForReactTag:reactTag];
50#endif // RCT_NEW_ARCH_ENABLED
51 return view;
52}
53
54- (NSArray<NSNumber *> *)startTransition:(NSNumber *)stackTag
55{
56 RCTAssertMainQueue();
57 RNSScreenStackView *stackView = [self getStackView:stackTag];
58 if (stackView == nil || isActiveTransition) {
59 return @[ @(-1), @(-1) ];
60 }
61 NSArray<NSNumber *> *screenTags = @[ @(-1), @(-1) ];
62 auto screens = stackView.reactViewController.childViewControllers;
63 unsigned long screenCount = [screens count];
64 if (screenCount > 1) {
65 UIView *topScreen = screens[screenCount - 1].view;
66 UIView *belowTopScreen = screens[screenCount - 2].view;
67 belowTopScreen.transform = CGAffineTransformMake(1, 0, 0, 1, 0, 0);
68 isActiveTransition = true;
69#ifdef RCT_NEW_ARCH_ENABLED
70 screenTags = @[ @(topScreen.tag), @(belowTopScreen.tag) ];
71#else
72 screenTags = @[ topScreen.reactTag, belowTopScreen.reactTag ];
73#endif // RCT_NEW_ARCH_ENABLED
74 [stackView startScreenTransition];
75 }
76 return screenTags;
77}
78
79- (bool)updateTransition:(NSNumber *)stackTag progress:(double)progress
80{
81 RCTAssertMainQueue();
82 RNSScreenStackView *stackView = [self getStackView:stackTag];
83 if (stackView == nil || !isActiveTransition) {
84 return false;
85 }
86 [stackView updateScreenTransition:progress];
87 return true;
88}
89
90- (bool)finishTransition:(NSNumber *)stackTag canceled:(bool)canceled
91{
92 RCTAssertMainQueue();
93 RNSScreenStackView *stackView = [self getStackView:stackTag];
94 if (stackView == nil || !isActiveTransition) {
95 return false;
96 }
97 [stackView finishScreenTransition:canceled];
98 if (!canceled) {
99 stackView.disableSwipeBack = NO;
100 }
101 isActiveTransition = false;
102 return true;
103}
104
105- (void)disableSwipeBackForTopScreen:(NSNumber *)stackTag
106{
107 RCTAssertMainQueue();
108 RNSScreenStackView *stackView = [self getStackView:stackTag];
109 if (stackView == nil) {
110 return;
111 }
112 stackView.disableSwipeBack = YES;
113}
114
115- (RNSScreenStackView *)getStackView:(NSNumber *)stackTag
116{
117 RNSScreenStackView *view = [self getScreenStackView:stackTag];
118 if (view != nil && ![view isKindOfClass:[RNSScreenStackView class]]) {
119 RCTLogError(@"Invalid view type, expecting RNSScreenStackView, got: %@", view);
120 return nil;
121 }
122 return view;
123}
124
125#ifdef RCT_NEW_ARCH_ENABLED
126- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
127 (const facebook::react::ObjCTurboModule::InitParams &)params
128{
129 [self installHostObject];
130 return std::make_shared<facebook::react::NativeScreensModuleSpecJSI>(params);
131}
132#endif
133
134- (void)installHostObject
135{
136 /*
137 installHostObject method is called from constantsToExport and getTurboModule,
138 because depending on the selected architecture, only one method will be called.
139 For `Paper`, it will be constantsToExport, and for `Fabric`, it will be getTurboModule.
140*/
141 RCTCxxBridge *cxxBridge = (RCTCxxBridge *)self.bridge;
142 if (cxxBridge != nil) {
143 auto jsiRuntime = (jsi::Runtime *)cxxBridge.runtime;
144 if (jsiRuntime != nil) {
145 auto &runtime = *jsiRuntime;
146 __weak auto weakSelf = self;
147
148 const auto &startTransition = [weakSelf](int stackTag) -> std::array<int, 2> {
149 auto screensTags = [weakSelf startTransition:@(stackTag)];
150 return {[screensTags[0] intValue], [screensTags[1] intValue]};
151 };
152 const auto &updateTransition = [weakSelf](int stackTag, double progress) {
153 [weakSelf updateTransition:@(stackTag) progress:progress];
154 };
155 const auto &finishTransition = [weakSelf](int stackTag, bool canceled) {
156 [weakSelf finishTransition:@(stackTag) canceled:canceled];
157 };
158 const auto &disableSwipeBackForTopScreen = [weakSelf](int stackTag) {
159 [weakSelf disableSwipeBackForTopScreen:@(stackTag)];
160 };
161
162 auto rnScreensModule = std::make_shared<RNScreens::RNScreensTurboModule>(
163 startTransition, updateTransition, finishTransition, disableSwipeBackForTopScreen);
164 auto rnScreensModuleHostObject = jsi::Object::createFromHostObject(runtime, rnScreensModule);
165 runtime.global().setProperty(
166 runtime, RNScreens::RNScreensTurboModule::MODULE_NAME, std::move(rnScreensModuleHostObject));
167 }
168 }
169}
170
171@end
172
173NS_ASSUME_NONNULL_END