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