1b987b50fSBen Roth// Copyright 2015-present 650 Industries. All rights reserved.
2b987b50fSBen Roth
39a7f140aSEric Samelson#import "EXEnvironment.h"
4b987b50fSBen Roth#import "EXHomeModule.h"
5*8a20a963SEric Samelson#import "EXSession.h"
6b987b50fSBen Roth#import "EXUnversioned.h"
7b987b50fSBen Roth
8b987b50fSBen Roth#import <React/RCTEventDispatcher.h>
9b987b50fSBen Roth
10b987b50fSBen Roth@interface EXHomeModule ()
11b987b50fSBen Roth
12b987b50fSBen Roth@property (nonatomic, assign) BOOL hasListeners;
13b987b50fSBen Roth@property (nonatomic, strong) NSMutableDictionary *eventSuccessBlocks;
14b987b50fSBen Roth@property (nonatomic, strong) NSMutableDictionary *eventFailureBlocks;
15b987b50fSBen Roth@property (nonatomic, strong) NSArray * _Nonnull sdkVersions;
16b987b50fSBen Roth@property (nonatomic, weak) id<EXHomeModuleDelegate> delegate;
17b987b50fSBen Roth
18b987b50fSBen Roth@end
19b987b50fSBen Roth
20b987b50fSBen Roth@implementation EXHomeModule
21b987b50fSBen Roth
22b987b50fSBen Roth+ (NSString *)moduleName { return @"ExponentKernel"; }
23b987b50fSBen Roth
24b987b50fSBen Roth- (instancetype)initWithExperienceId:(NSString *)experienceId kernelServiceDelegate:(id)kernelServiceInstance params:(NSDictionary *)params
25b987b50fSBen Roth{
26b987b50fSBen Roth  if (self = [super initWithExperienceId:experienceId kernelServiceDelegate:kernelServiceInstance params:params]) {
27b987b50fSBen Roth    _eventSuccessBlocks = [NSMutableDictionary dictionary];
28b987b50fSBen Roth    _eventFailureBlocks = [NSMutableDictionary dictionary];
29b987b50fSBen Roth    _sdkVersions = params[@"supportedSdkVersions"];
30b987b50fSBen Roth    _delegate = kernelServiceInstance;
31b987b50fSBen Roth  }
32b987b50fSBen Roth  return self;
33b987b50fSBen Roth}
34b987b50fSBen Roth
35b987b50fSBen Roth+ (BOOL)requiresMainQueueSetup
36b987b50fSBen Roth{
37b987b50fSBen Roth  return NO;
38b987b50fSBen Roth}
39b987b50fSBen Roth
40b987b50fSBen Roth- (NSDictionary *)constantsToExport
41b987b50fSBen Roth{
42b987b50fSBen Roth  return @{ @"sdkVersions": _sdkVersions };
43b987b50fSBen Roth}
44b987b50fSBen Roth
45b987b50fSBen Roth#pragma mark - RCTEventEmitter methods
46b987b50fSBen Roth
47b987b50fSBen Roth- (NSArray<NSString *> *)supportedEvents
48b987b50fSBen Roth{
49b987b50fSBen Roth  return @[];
50b987b50fSBen Roth}
51b987b50fSBen Roth
52b987b50fSBen Roth/**
53b987b50fSBen Roth *  Override this method to avoid the [self supportedEvents] validation
54b987b50fSBen Roth */
55b987b50fSBen Roth- (void)sendEventWithName:(NSString *)eventName body:(id)body
56b987b50fSBen Roth{
57b987b50fSBen Roth  // Note that this could be a versioned bridge!
58b987b50fSBen Roth  [self.bridge enqueueJSCall:@"RCTDeviceEventEmitter.emit"
59b987b50fSBen Roth                        args:body ? @[eventName, body] : @[eventName]];
60b987b50fSBen Roth}
61b987b50fSBen Roth
62b987b50fSBen Roth#pragma mark -
63b987b50fSBen Roth
64b987b50fSBen Roth- (void)dispatchJSEvent:(NSString *)eventName body:(NSDictionary *)eventBody onSuccess:(void (^)(NSDictionary *))success onFailure:(void (^)(NSString *))failure
65b987b50fSBen Roth{
66b987b50fSBen Roth  NSString *qualifiedEventName = [NSString stringWithFormat:@"ExponentKernel.%@", eventName];
67b987b50fSBen Roth  NSMutableDictionary *qualifiedEventBody = (eventBody) ? [eventBody mutableCopy] : [NSMutableDictionary dictionary];
68b987b50fSBen Roth
69b987b50fSBen Roth  if (success && failure) {
70b987b50fSBen Roth    NSString *eventId = [[NSUUID UUID] UUIDString];
71b987b50fSBen Roth    [_eventSuccessBlocks setObject:success forKey:eventId];
72b987b50fSBen Roth    [_eventFailureBlocks setObject:failure forKey:eventId];
73b987b50fSBen Roth    [qualifiedEventBody setObject:eventId forKey:@"eventId"];
74b987b50fSBen Roth  }
75b987b50fSBen Roth
76b987b50fSBen Roth  [self sendEventWithName:qualifiedEventName body:qualifiedEventBody];
77b987b50fSBen Roth}
78b987b50fSBen Roth
79b987b50fSBen Roth/**
80b987b50fSBen Roth *  Duplicates Linking.openURL but does not validate that this is an exponent URL;
81b987b50fSBen Roth *  in other words, we just take your word for it and never hand it off to iOS.
82b987b50fSBen Roth *  Used by the home screen URL bar.
83b987b50fSBen Roth */
84b987b50fSBen RothRCT_EXPORT_METHOD(openURL:(NSURL *)URL
85b987b50fSBen Roth                  resolve:(RCTPromiseResolveBlock)resolve
86b987b50fSBen Roth                  reject:(__unused RCTPromiseRejectBlock)reject)
87b987b50fSBen Roth{
88b987b50fSBen Roth  if (URL) {
89b987b50fSBen Roth    [_delegate homeModule:self didOpenUrl:URL.absoluteString];
90b987b50fSBen Roth    resolve(@YES);
91b987b50fSBen Roth  } else {
92b987b50fSBen Roth    NSError *err = [NSError errorWithDomain:EX_UNVERSIONED(@"EXKernelErrorDomain") code:-1 userInfo:@{ NSLocalizedDescriptionKey: @"Cannot open a nil url" }];
93b987b50fSBen Roth    reject(@"E_INVALID_URL", err.localizedDescription, err);
94b987b50fSBen Roth  }
95b987b50fSBen Roth}
96b987b50fSBen Roth
97b987b50fSBen RothRCT_REMAP_METHOD(doesCurrentTaskEnableDevtools,
98b987b50fSBen Roth                 doesCurrentTaskEnableDevtoolsWithResolver:(RCTPromiseResolveBlock)resolve
99b987b50fSBen Roth                 reject:(RCTPromiseRejectBlock)reject)
100b987b50fSBen Roth{
101b987b50fSBen Roth  if (_delegate) {
102b987b50fSBen Roth    resolve(@([_delegate homeModuleShouldEnableDevtools:self]));
103b987b50fSBen Roth  } else {
104b987b50fSBen Roth    // don't reject, just disable devtools
105b987b50fSBen Roth    resolve(@NO);
106b987b50fSBen Roth  }
107b987b50fSBen Roth}
108b987b50fSBen Roth
109b987b50fSBen RothRCT_REMAP_METHOD(isLegacyMenuBehaviorEnabledAsync,
110b987b50fSBen Roth                 isLegacyMenuBehaviorEnabledWithResolver:(RCTPromiseResolveBlock)resolve
111b987b50fSBen Roth                 rejecter:(RCTPromiseRejectBlock)reject)
112b987b50fSBen Roth{
113b987b50fSBen Roth  if (_delegate) {
114b987b50fSBen Roth    resolve(@([_delegate homeModuleShouldEnableLegacyMenuBehavior:self]));
115b987b50fSBen Roth  } else {
116b987b50fSBen Roth    resolve(@(NO));
117b987b50fSBen Roth  }
118b987b50fSBen Roth}
119b987b50fSBen Roth
120b987b50fSBen RothRCT_EXPORT_METHOD(setIsLegacyMenuBehaviorEnabledAsync:(BOOL)isEnabled)
121b987b50fSBen Roth{
122b987b50fSBen Roth  if (_delegate) {
123b987b50fSBen Roth    [_delegate homeModule:self didSelectEnableLegacyMenuBehavior:isEnabled];
124b987b50fSBen Roth  }
125b987b50fSBen Roth}
126b987b50fSBen Roth
127b987b50fSBen RothRCT_REMAP_METHOD(getDevMenuItemsToShow,
128b987b50fSBen Roth                 getDevMenuItemsToShowWithResolver:(RCTPromiseResolveBlock)resolve
129b987b50fSBen Roth                 reject:(RCTPromiseRejectBlock)reject)
130b987b50fSBen Roth{
131b987b50fSBen Roth  if (_delegate && [_delegate homeModuleShouldEnableDevtools:self]) {
132b987b50fSBen Roth    resolve([_delegate devMenuItemsForHomeModule:self]);
133b987b50fSBen Roth  } else {
134b987b50fSBen Roth    // don't reject, just show no devtools
135b987b50fSBen Roth    resolve(@{});
136b987b50fSBen Roth  }
137b987b50fSBen Roth}
138b987b50fSBen Roth
139b987b50fSBen RothRCT_EXPORT_METHOD(selectDevMenuItemWithKey:(NSString *)key)
140b987b50fSBen Roth{
141b987b50fSBen Roth  if (_delegate) {
142b987b50fSBen Roth    [_delegate homeModule:self didSelectDevMenuItemWithKey:key];
143b987b50fSBen Roth  }
144b987b50fSBen Roth}
145b987b50fSBen Roth
146b987b50fSBen RothRCT_EXPORT_METHOD(selectRefresh)
147b987b50fSBen Roth{
148b987b50fSBen Roth  if (_delegate) {
149b987b50fSBen Roth    [_delegate homeModuleDidSelectRefresh:self];
150b987b50fSBen Roth  }
151b987b50fSBen Roth}
152b987b50fSBen Roth
153b987b50fSBen RothRCT_EXPORT_METHOD(selectCloseMenu)
154b987b50fSBen Roth{
155b987b50fSBen Roth  if (_delegate) {
156b987b50fSBen Roth    [_delegate homeModuleDidSelectCloseMenu:self];
157b987b50fSBen Roth  }
158b987b50fSBen Roth}
159b987b50fSBen Roth
160b987b50fSBen RothRCT_EXPORT_METHOD(selectGoToHome)
161b987b50fSBen Roth{
162b987b50fSBen Roth  if (_delegate) {
163b987b50fSBen Roth    [_delegate homeModuleDidSelectGoToHome:self];
164b987b50fSBen Roth  }
165b987b50fSBen Roth}
166b987b50fSBen Roth
1672fcba380SBen RothRCT_EXPORT_METHOD(selectQRReader)
1682fcba380SBen Roth{
1692fcba380SBen Roth  if (_delegate) {
1702fcba380SBen Roth    [_delegate homeModuleDidSelectQRReader:self];
1712fcba380SBen Roth  }
1722fcba380SBen Roth}
1732fcba380SBen Roth
174*8a20a963SEric SamelsonRCT_REMAP_METHOD(getSessionAsync,
175*8a20a963SEric Samelson                 getSessionAsync:(RCTPromiseResolveBlock)resolve
176*8a20a963SEric Samelson                 rejecter:(RCTPromiseRejectBlock)reject)
1779a7f140aSEric Samelson{
178*8a20a963SEric Samelson  NSDictionary *session = [[EXSession sharedInstance] session];
179*8a20a963SEric Samelson  resolve(session);
1809a7f140aSEric Samelson}
1819a7f140aSEric Samelson
182*8a20a963SEric SamelsonRCT_REMAP_METHOD(setSessionAsync,
183*8a20a963SEric Samelson                 setSessionAsync:(NSDictionary *)session
184*8a20a963SEric Samelson                 resolver:(RCTPromiseResolveBlock)resolve
185*8a20a963SEric Samelson                 rejecter:(RCTPromiseRejectBlock)reject)
1869a7f140aSEric Samelson{
187*8a20a963SEric Samelson  NSError *error;
188*8a20a963SEric Samelson  BOOL success = [[EXSession sharedInstance] saveSessionToKeychain:session error:&error];
189*8a20a963SEric Samelson  if (success) {
190*8a20a963SEric Samelson    resolve(nil);
191*8a20a963SEric Samelson  } else {
192*8a20a963SEric Samelson    reject(@"ERR_SESSION_NOT_SAVED", @"Could not save session", error);
193*8a20a963SEric Samelson  }
194*8a20a963SEric Samelson}
195*8a20a963SEric Samelson
196*8a20a963SEric SamelsonRCT_REMAP_METHOD(removeSessionAsync,
197*8a20a963SEric Samelson                 removeSessionAsync:(RCTPromiseResolveBlock)resolve
198*8a20a963SEric Samelson                 rejecter:(RCTPromiseRejectBlock)reject)
199*8a20a963SEric Samelson{
200*8a20a963SEric Samelson  NSError *error;
201*8a20a963SEric Samelson  BOOL success = [[EXSession sharedInstance] deleteSessionFromKeychainWithError:&error];
202*8a20a963SEric Samelson  if (success) {
203*8a20a963SEric Samelson    resolve(nil);
204*8a20a963SEric Samelson  } else {
205*8a20a963SEric Samelson    reject(@"ERR_SESSION_NOT_REMOVED", @"Could not remove session", error);
206*8a20a963SEric Samelson  }
2079a7f140aSEric Samelson}
2089a7f140aSEric Samelson
209b987b50fSBen RothRCT_EXPORT_METHOD(addDevMenu)
210b987b50fSBen Roth{
211b987b50fSBen Roth  __weak typeof(self) weakSelf = self;
212b987b50fSBen Roth  dispatch_async(dispatch_get_main_queue(), ^{
213b987b50fSBen Roth    if (weakSelf.delegate) {
214b987b50fSBen Roth      [weakSelf.delegate homeModuleDidSelectHomeDiagnostics:self];
215b987b50fSBen Roth    }
216b987b50fSBen Roth  });
217b987b50fSBen Roth}
218b987b50fSBen Roth
21966169681SBen RothRCT_REMAP_METHOD(getIsNuxFinishedAsync,
22066169681SBen Roth                 getIsNuxFinishedWithResolver:(RCTPromiseResolveBlock)resolve
22166169681SBen Roth                 rejecter:(RCTPromiseRejectBlock)reject)
222b987b50fSBen Roth{
22366169681SBen Roth  if (_delegate) {
22466169681SBen Roth    BOOL isFinished = [_delegate homeModuleShouldFinishNux:self];
22566169681SBen Roth    resolve(@(isFinished));
22666169681SBen Roth  } else {
22766169681SBen Roth    resolve(@(NO));
22866169681SBen Roth  }
22966169681SBen Roth}
23066169681SBen Roth
23166169681SBen RothRCT_REMAP_METHOD(setIsNuxFinishedAsync,
23266169681SBen Roth                 setIsNuxFinished:(BOOL)isNuxFinished)
23366169681SBen Roth{
23466169681SBen Roth  if (_delegate) {
23566169681SBen Roth    [_delegate homeModule:self didFinishNux:isNuxFinished];
23666169681SBen Roth  }
237b987b50fSBen Roth}
238b987b50fSBen Roth
239b987b50fSBen RothRCT_REMAP_METHOD(onEventSuccess,
240b987b50fSBen Roth                 eventId:(NSString *)eventId
241b987b50fSBen Roth                 body:(NSDictionary *)body)
242b987b50fSBen Roth{
243b987b50fSBen Roth  void (^success)(NSDictionary *) = [_eventSuccessBlocks objectForKey:eventId];
244b987b50fSBen Roth  if (success) {
245b987b50fSBen Roth    success(body);
246b987b50fSBen Roth    [_eventSuccessBlocks removeObjectForKey:eventId];
247b987b50fSBen Roth    [_eventFailureBlocks removeObjectForKey:eventId];
248b987b50fSBen Roth  }
249b987b50fSBen Roth}
250b987b50fSBen Roth
251b987b50fSBen RothRCT_REMAP_METHOD(onEventFailure,
252b987b50fSBen Roth                 eventId:(NSString *)eventId
253b987b50fSBen Roth                 message:(NSString *)message)
254b987b50fSBen Roth{
255b987b50fSBen Roth  void (^failure)(NSString *) = [_eventFailureBlocks objectForKey:eventId];
256b987b50fSBen Roth  if (failure) {
257b987b50fSBen Roth    failure(message);
258b987b50fSBen Roth    [_eventSuccessBlocks removeObjectForKey:eventId];
259b987b50fSBen Roth    [_eventFailureBlocks removeObjectForKey:eventId];
260b987b50fSBen Roth  }
261b987b50fSBen Roth}
262b987b50fSBen Roth
263b987b50fSBen Roth@end
264